<!doctype html>
<html class="no-js" lang="en" data-content_root="../../../">
  <head><meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="../../../genindex.html"><link rel="search" title="Search" href="../../../search.html">

    <!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25 -->
        <title>osxphotos.photosdb.photosdb - osxphotos 0.74.2 documentation</title>
      <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=d111a655" />
    <link rel="stylesheet" type="text/css" href="../../../_static/styles/furo.css?v=580074bf" />
    <link rel="stylesheet" type="text/css" href="../../../_static/copybutton.css?v=76b2166b" />
    <link rel="stylesheet" type="text/css" href="../../../_static/styles/furo-extensions.css?v=8dab3a3b" />
    
    


<style>
  body {
    --color-code-background: #f2f2f2;
  --color-code-foreground: #1e1e1e;
  
  }
  @media not print {
    body[data-theme="dark"] {
      --color-code-background: #202020;
  --color-code-foreground: #d0d0d0;
  
    }
    @media (prefers-color-scheme: dark) {
      body:not([data-theme="light"]) {
        --color-code-background: #202020;
  --color-code-foreground: #d0d0d0;
  
      }
    }
  }
</style></head>
  <body>
    
    <script>
      document.body.dataset.theme = localStorage.getItem("theme") || "auto";
    </script>
    

<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="svg-toc" viewBox="0 0 24 24">
    <title>Contents</title>
    <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024">
      <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM115.4 518.9L271.7 642c5.8 4.6 14.4.5 14.4-6.9V388.9c0-7.4-8.5-11.5-14.4-6.9L115.4 505.1a8.74 8.74 0 0 0 0 13.8z"/>
    </svg>
  </symbol>
  <symbol id="svg-menu" viewBox="0 0 24 24">
    <title>Menu</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-menu">
      <line x1="3" y1="12" x2="21" y2="12"></line>
      <line x1="3" y1="6" x2="21" y2="6"></line>
      <line x1="3" y1="18" x2="21" y2="18"></line>
    </svg>
  </symbol>
  <symbol id="svg-arrow-right" viewBox="0 0 24 24">
    <title>Expand</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-chevron-right">
      <polyline points="9 18 15 12 9 6"></polyline>
    </svg>
  </symbol>
  <symbol id="svg-sun" viewBox="0 0 24 24">
    <title>Light mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="feather-sun">
      <circle cx="12" cy="12" r="5"></circle>
      <line x1="12" y1="1" x2="12" y2="3"></line>
      <line x1="12" y1="21" x2="12" y2="23"></line>
      <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
      <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
      <line x1="1" y1="12" x2="3" y2="12"></line>
      <line x1="21" y1="12" x2="23" y2="12"></line>
      <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
      <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
    </svg>
  </symbol>
  <symbol id="svg-moon" viewBox="0 0 24 24">
    <title>Dark mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-moon">
      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
      <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
    </svg>
  </symbol>
  <symbol id="svg-sun-with-moon" viewBox="0 0 24 24">
    <title>Auto light/dark, in light mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
      class="icon-custom-derived-from-feather-sun-and-tabler-moon">
      <path style="opacity: 50%" d="M 5.411 14.504 C 5.471 14.504 5.532 14.504 5.591 14.504 C 3.639 16.319 4.383 19.569 6.931 20.352 C 7.693 20.586 8.512 20.551 9.25 20.252 C 8.023 23.207 4.056 23.725 2.11 21.184 C 0.166 18.642 1.702 14.949 4.874 14.536 C 5.051 14.512 5.231 14.5 5.411 14.5 L 5.411 14.504 Z"/>
      <line x1="14.5" y1="3.25" x2="14.5" y2="1.25"/>
      <line x1="14.5" y1="15.85" x2="14.5" y2="17.85"/>
      <line x1="10.044" y1="5.094" x2="8.63" y2="3.68"/>
      <line x1="19" y1="14.05" x2="20.414" y2="15.464"/>
      <line x1="8.2" y1="9.55" x2="6.2" y2="9.55"/>
      <line x1="20.8" y1="9.55" x2="22.8" y2="9.55"/>
      <line x1="10.044" y1="14.006" x2="8.63" y2="15.42"/>
      <line x1="19" y1="5.05" x2="20.414" y2="3.636"/>
      <circle cx="14.5" cy="9.55" r="3.6"/>
    </svg>
  </symbol>
  <symbol id="svg-moon-with-sun" viewBox="0 0 24 24">
    <title>Auto light/dark, in dark mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
      class="icon-custom-derived-from-feather-sun-and-tabler-moon">
      <path d="M 8.282 7.007 C 8.385 7.007 8.494 7.007 8.595 7.007 C 5.18 10.184 6.481 15.869 10.942 17.24 C 12.275 17.648 13.706 17.589 15 17.066 C 12.851 22.236 5.91 23.143 2.505 18.696 C -0.897 14.249 1.791 7.786 7.342 7.063 C 7.652 7.021 7.965 7 8.282 7 L 8.282 7.007 Z"/>
      <line style="opacity: 50%" x1="18" y1="3.705" x2="18" y2="2.5"/>
      <line style="opacity: 50%" x1="18" y1="11.295" x2="18" y2="12.5"/>
      <line style="opacity: 50%" x1="15.316" y1="4.816" x2="14.464" y2="3.964"/>
      <line style="opacity: 50%" x1="20.711" y1="10.212" x2="21.563" y2="11.063"/>
      <line style="opacity: 50%" x1="14.205" y1="7.5" x2="13.001" y2="7.5"/>
      <line style="opacity: 50%" x1="21.795" y1="7.5" x2="23" y2="7.5"/>
      <line style="opacity: 50%" x1="15.316" y1="10.184" x2="14.464" y2="11.036"/>
      <line style="opacity: 50%" x1="20.711" y1="4.789" x2="21.563" y2="3.937"/>
      <circle style="opacity: 50%" cx="18" cy="7.5" r="2.169"/>
    </svg>
  </symbol>
  <symbol id="svg-pencil" viewBox="0 0 24 24">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-pencil-code">
      <path d="M4 20h4l10.5 -10.5a2.828 2.828 0 1 0 -4 -4l-10.5 10.5v4" />
      <path d="M13.5 6.5l4 4" />
      <path d="M20 21l2 -2l-2 -2" />
      <path d="M17 17l-2 2l2 2" />
    </svg>
  </symbol>
  <symbol id="svg-eye" viewBox="0 0 24 24">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-eye-code">
      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
      <path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
      <path
        d="M11.11 17.958c-3.209 -.307 -5.91 -2.293 -8.11 -5.958c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6c-.21 .352 -.427 .688 -.647 1.008" />
      <path d="M20 21l2 -2l-2 -2" />
      <path d="M17 17l-2 2l2 2" />
    </svg>
  </symbol>
</svg>

<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation" aria-label="Toggle site navigation sidebar">
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc" aria-label="Toggle table of contents sidebar">
<label class="overlay sidebar-overlay" for="__navigation"></label>
<label class="overlay toc-overlay" for="__toc"></label>

<a class="skip-to-content muted-link" href="#furo-main-content">Skip to content</a>



<div class="page">
  <header class="mobile-header">
    <div class="header-left">
      <label class="nav-overlay-icon" for="__navigation">
        <span class="icon"><svg><use href="#svg-menu"></use></svg></span>
      </label>
    </div>
    <div class="header-center">
      <a href="../../../index.html"><div class="brand">osxphotos 0.74.2 documentation</div></a>
    </div>
    <div class="header-right">
      <div class="theme-toggle-container theme-toggle-header">
        <button class="theme-toggle" aria-label="Toggle Light / Dark / Auto color theme">
          <svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
          <svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
          <svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
          <svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
        </button>
      </div>
      <label class="toc-overlay-icon toc-header-icon no-toc" for="__toc">
        <span class="icon"><svg><use href="#svg-toc"></use></svg></span>
      </label>
    </div>
  </header>
  <aside class="sidebar-drawer">
    <div class="sidebar-container">
      
      <div class="sidebar-sticky"><a class="sidebar-brand" href="../../../index.html">
  
  <span class="sidebar-brand-text">osxphotos 0.74.2 documentation</span>
  
</a><form class="sidebar-search-container" method="get" action="../../../search.html" role="search">
  <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
  <input type="hidden" name="check_keywords" value="yes">
  <input type="hidden" name="area" value="default">
</form>
<div id="searchbox"></div><div class="sidebar-scroll"><div class="sidebar-tree">
  <ul>
<li class="toctree-l1"><a class="reference internal" href="../../../overview.html">OSXPhotos</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../tutorial.html">OSXPhotos Tutorial</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../cli.html">OSXPhotos Command Line Interface (CLI)</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../template_help.html">OSXPhotos Template System</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../package_overview.html">OSXPhotos Python Package Overview</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../API_README.html">OSXPhotos Python API</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../../reference.html">OSXPhotos Python Reference</a></li>
</ul>

</div>
</div>

      </div>
      
    </div>
  </aside>
  <div class="main">
    <div class="content">
      <div class="article-container">
        <a href="#" class="back-to-top muted-link">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
            <path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12z"></path>
          </svg>
          <span>Back to top</span>
        </a>
        <div class="content-icon-container">
          <div class="theme-toggle-container theme-toggle-content">
            <button class="theme-toggle" aria-label="Toggle Light / Dark / Auto color theme">
              <svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
              <svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
              <svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
              <svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
            </button>
          </div>
          <label class="toc-overlay-icon toc-content-icon no-toc" for="__toc">
            <span class="icon"><svg><use href="#svg-toc"></use></svg></span>
          </label>
        </div>
        <article role="main" id="furo-main-content">
          <h1>Source code for osxphotos.photosdb.photosdb</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">PhotosDB class</span>
<span class="sd">Processes a Photos.app library database to extract information about photos</span>
<span class="sd">&quot;&quot;&quot;</span>

<span class="kn">from</span><span class="w"> </span><span class="nn">__future__</span><span class="w"> </span><span class="kn">import</span> <span class="n">annotations</span>

<span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os.path</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">pathlib</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">platform</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">sqlite3</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">sys</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">tempfile</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span><span class="p">,</span> <span class="n">timezone</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">Optional</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">unicodedata</span><span class="w"> </span><span class="kn">import</span> <span class="n">normalize</span>

<span class="kn">from</span><span class="w"> </span><span class="nn">rich</span><span class="w"> </span><span class="kn">import</span> <span class="nb">print</span>

<span class="kn">from</span><span class="w"> </span><span class="nn">osxphotos.platform</span><span class="w"> </span><span class="kn">import</span> <span class="n">check_and_warn_macos_version</span>

<span class="kn">from</span><span class="w"> </span><span class="nn">.._constants</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
    <span class="n">_DB_TABLE_NAMES</span><span class="p">,</span>
    <span class="n">_MOVIE_TYPE</span><span class="p">,</span>
    <span class="n">_PHOTO_TYPE</span><span class="p">,</span>
    <span class="n">_PHOTOS_3_VERSION</span><span class="p">,</span>
    <span class="n">_PHOTOS_4_ALBUM_KIND</span><span class="p">,</span>
    <span class="n">_PHOTOS_4_ALBUM_TYPE_ALBUM</span><span class="p">,</span>
    <span class="n">_PHOTOS_4_ALBUM_TYPE_PROJECT</span><span class="p">,</span>
    <span class="n">_PHOTOS_4_ALBUM_TYPE_SLIDESHOW</span><span class="p">,</span>
    <span class="n">_PHOTOS_4_ROOT_FOLDER</span><span class="p">,</span>
    <span class="n">_PHOTOS_4_TOP_LEVEL_ALBUMS</span><span class="p">,</span>
    <span class="n">_PHOTOS_4_VERSION</span><span class="p">,</span>
    <span class="n">_PHOTOS_5_ALBUM_KIND</span><span class="p">,</span>
    <span class="n">_PHOTOS_5_FOLDER_KIND</span><span class="p">,</span>
    <span class="n">_PHOTOS_5_IMPORT_SESSION_ALBUM_KIND</span><span class="p">,</span>
    <span class="n">_PHOTOS_5_PROJECT_ALBUM_KIND</span><span class="p">,</span>
    <span class="n">_PHOTOS_5_ROOT_FOLDER_KIND</span><span class="p">,</span>
    <span class="n">_PHOTOS_5_SHARED_ALBUM_KIND</span><span class="p">,</span>
    <span class="n">_UNKNOWN_PERSON</span><span class="p">,</span>
    <span class="n">BURST_KEY</span><span class="p">,</span>
    <span class="n">BURST_PICK_TYPE_NONE</span><span class="p">,</span>
    <span class="n">BURST_SELECTED</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.._version</span><span class="w"> </span><span class="kn">import</span> <span class="n">__version__</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..albuminfo</span><span class="w"> </span><span class="kn">import</span> <span class="n">AlbumInfo</span><span class="p">,</span> <span class="n">FolderInfo</span><span class="p">,</span> <span class="n">ImportInfo</span><span class="p">,</span> <span class="n">ProjectInfo</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..datetime_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime_has_tz</span><span class="p">,</span> <span class="n">datetime_naive_to_local</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..fileutil</span><span class="w"> </span><span class="kn">import</span> <span class="n">FileUtil</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..iphoto</span><span class="w"> </span><span class="kn">import</span> <span class="n">is_iphoto_library</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..personinfo</span><span class="w"> </span><span class="kn">import</span> <span class="n">PersonInfo</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..photoinfo</span><span class="w"> </span><span class="kn">import</span> <span class="n">PhotoInfo</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..photoquery</span><span class="w"> </span><span class="kn">import</span> <span class="n">QueryOptions</span><span class="p">,</span> <span class="n">photo_query</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..photos_datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">photos_datetime</span><span class="p">,</span> <span class="n">photos_datetime_local</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..platform</span><span class="w"> </span><span class="kn">import</span> <span class="n">is_macos</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..rich_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">add_rich_markup_tag</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..sqlite_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">sqlite_db_is_locked</span><span class="p">,</span> <span class="n">sqlite_open_ro</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..unicode</span><span class="w"> </span><span class="kn">import</span> <span class="n">normalize_unicode</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">..utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">_check_file_exists</span><span class="p">,</span> <span class="n">get_last_library_path</span><span class="p">,</span> <span class="n">noop</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.photosdb_utils</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
    <span class="n">get_db_version</span><span class="p">,</span>
    <span class="n">get_model_version</span><span class="p">,</span>
    <span class="n">get_photos_version_from_model</span><span class="p">,</span>
<span class="p">)</span>

<span class="k">if</span> <span class="n">is_macos</span><span class="p">:</span>
    <span class="kn">import</span><span class="w"> </span><span class="nn">photoscript</span>

<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s2">&quot;osxphotos&quot;</span><span class="p">)</span>

<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;PhotosDB&quot;</span><span class="p">,</span> <span class="s2">&quot;PhotosDBReadError&quot;</span><span class="p">]</span>

<span class="c1"># TODO: Add test for imageTimeZoneOffsetSeconds = None</span>
<span class="c1"># TODO: Add test for __str__</span>
<span class="c1"># TODO: Add special albums and magic albums</span>


<span class="k">class</span><span class="w"> </span><span class="nc">PhotosDBReadError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Generic error when reading the Photos database&quot;&quot;&quot;</span>

    <span class="k">pass</span>


<div class="viewcode-block" id="PhotosDB">
<a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">PhotosDB</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Processes a Photos.app library database to extract information about photos&quot;&quot;&quot;</span>

    <span class="c1"># import additional methods</span>
    <span class="kn">from</span><span class="w"> </span><span class="nn">._photosdb_process_comments</span><span class="w"> </span><span class="kn">import</span> <span class="n">_process_comments</span>
    <span class="kn">from</span><span class="w"> </span><span class="nn">._photosdb_process_exif</span><span class="w"> </span><span class="kn">import</span> <span class="n">_process_exifinfo</span>
    <span class="kn">from</span><span class="w"> </span><span class="nn">._photosdb_process_faceinfo</span><span class="w"> </span><span class="kn">import</span> <span class="n">_process_faceinfo</span>
    <span class="kn">from</span><span class="w"> </span><span class="nn">._photosdb_process_scoreinfo</span><span class="w"> </span><span class="kn">import</span> <span class="n">_process_scoreinfo</span>
    <span class="kn">from</span><span class="w"> </span><span class="nn">._photosdb_process_searchinfo</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
        <span class="n">_process_searchinfo</span><span class="p">,</span>
        <span class="n">labels</span><span class="p">,</span>
        <span class="n">labels_as_dict</span><span class="p">,</span>
        <span class="n">labels_normalized</span><span class="p">,</span>
        <span class="n">labels_normalized_as_dict</span><span class="p">,</span>
    <span class="p">)</span>
    <span class="kn">from</span><span class="w"> </span><span class="nn">._photosdb_process_shared_library</span><span class="w"> </span><span class="kn">import</span> <span class="n">_process_shared_library_info</span>
    <span class="kn">from</span><span class="w"> </span><span class="nn">._photosdb_process_syndicationinfo</span><span class="w"> </span><span class="kn">import</span> <span class="n">_process_syndicationinfo</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span>
        <span class="n">dbfile</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
        <span class="n">verbose</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
        <span class="n">exiftool</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
        <span class="n">rich</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
        <span class="n">library_path</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
        <span class="n">_skip_searchinfo</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
    <span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Create a new PhotosDB object.</span>

<span class="sd">        Args:</span>
<span class="sd">            dbfile: specify full path to photos library or photos.db; if None, will attempt to locate last library opened by Photos.</span>
<span class="sd">            verbose: optional callable function to use for printing verbose text during processing; if None (default), does not print output.</span>
<span class="sd">            exiftool: optional path to exiftool for methods that require this (e.g. PhotoInfo.exiftool); if not provided, will search PATH</span>
<span class="sd">            rich: use rich with verbose output</span>
<span class="sd">            library_path: path to Photos library root if different than where the database is stored; see Notes</span>
<span class="sd">            _skip_searchinfo: if True, will not process search data from psi.sqlite; useful for processing standalone Photos.sqlite file</span>

<span class="sd">        Raises:</span>
<span class="sd">            PhotosDBReadError if dbfile is not a valid Photos library.</span>
<span class="sd">            TypeError if verbose is not None and not callable.</span>

<span class="sd">        Notes:</span>
<span class="sd">            dbfile can be either the path to the Photos library (e.g. ~/Pictures/Photos Library.photoslibrary)</span>
<span class="sd">            or the path to the photos.db file (e.g. ~/Pictures/Photos Library.photoslibrary/database/photos.db)</span>
<span class="sd">            or the path to the Photos.sqlite file (e.g. ~/Pictures/Photos Library.photoslibrary/database/Photos.sqlite)</span>
<span class="sd">            If dbfile is None, will attempt to locate last opened Photos library.</span>
<span class="sd">            In some cases, it may be useful to copy the database to a different location than the library</span>
<span class="sd">            (e.g. if the library is on a slow drive or an iPhone).</span>
<span class="sd">            In that case, set dbfile to the path to the database and set library_path to the path to the library root.</span>
<span class="sd">            For example:</span>

<span class="sd">            &#39;&#39;&#39;python</span>
<span class="sd">            photosdb = PhotosDB(dbfile=&quot;/path/to/database/Photos.sqlite&quot;, library_path=&quot;/path/to/Photos Library.photoslibrary&quot;)</span>
<span class="sd">            &#39;&#39;&#39;</span>

<span class="sd">            If library_path is not provided, PhotosDB determine the library path from the database path. In most cases you should</span>
<span class="sd">            not provide the library_path argument.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Check that we&#39;re not trying to open an iPhoto library</span>
        <span class="k">if</span> <span class="n">dbfile</span> <span class="ow">and</span> <span class="n">is_iphoto_library</span><span class="p">(</span><span class="n">dbfile</span><span class="p">):</span>
            <span class="k">raise</span> <span class="n">PhotosDBReadError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">dbfile</span><span class="si">}</span><span class="s2"> is an iPhoto library, not Photos&quot;</span><span class="p">)</span>

        <span class="n">check_and_warn_macos_version</span><span class="p">()</span>

        <span class="k">if</span> <span class="n">verbose</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">verbose</span> <span class="o">=</span> <span class="n">noop</span>
        <span class="k">elif</span> <span class="ow">not</span> <span class="nb">callable</span><span class="p">(</span><span class="n">verbose</span><span class="p">):</span>
            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&quot;verbose must be callable&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_verbose</span> <span class="o">=</span> <span class="n">verbose</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_skip_searchinfo</span> <span class="o">=</span> <span class="n">_skip_searchinfo</span>

        <span class="c1"># define functions for adding markup</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_filepath</span> <span class="o">=</span> <span class="n">add_rich_markup_tag</span><span class="p">(</span><span class="s2">&quot;filepath&quot;</span><span class="p">,</span> <span class="n">rich</span><span class="o">=</span><span class="n">rich</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_filename</span> <span class="o">=</span> <span class="n">add_rich_markup_tag</span><span class="p">(</span><span class="s2">&quot;filename&quot;</span><span class="p">,</span> <span class="n">rich</span><span class="o">=</span><span class="n">rich</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span> <span class="o">=</span> <span class="n">add_rich_markup_tag</span><span class="p">(</span><span class="s2">&quot;uuid&quot;</span><span class="p">,</span> <span class="n">rich</span><span class="o">=</span><span class="n">rich</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_num</span> <span class="o">=</span> <span class="n">add_rich_markup_tag</span><span class="p">(</span><span class="s2">&quot;num&quot;</span><span class="p">,</span> <span class="n">rich</span><span class="o">=</span><span class="n">rich</span><span class="p">)</span>

        <span class="c1"># enable beta features</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_beta</span> <span class="o">=</span> <span class="kc">False</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_exiftool_path</span> <span class="o">=</span> <span class="n">exiftool</span>

        <span class="c1"># create a temporary directory</span>
        <span class="c1"># tempfile.TemporaryDirectory gets cleaned up when the object does</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_tempdir</span> <span class="o">=</span> <span class="n">tempfile</span><span class="o">.</span><span class="n">TemporaryDirectory</span><span class="p">(</span><span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;osxphotos_&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_tempdir_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_tempdir</span><span class="o">.</span><span class="n">name</span>

        <span class="c1"># set up the data structures used to store all the Photo database info</span>

        <span class="c1"># TODO: I don&#39;t think these keywords flags are actually used</span>
        <span class="c1"># if True, will treat persons as keywords when exporting metadata</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">use_persons_as_keywords</span> <span class="o">=</span> <span class="kc">False</span>

        <span class="c1"># if True, will treat albums as keywords when exporting metadata</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">use_albums_as_keywords</span> <span class="o">=</span> <span class="kc">False</span>

        <span class="c1"># Path to the Photos library database file</span>
        <span class="c1"># photos.db in the photos library database/ directory</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="c1"># the actual file with library data</span>
        <span class="c1"># in Photos 5 this is Photos.sqlite instead of photos.db</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="c1"># Dict with information about all photos by uuid</span>
        <span class="c1"># This is the &quot;master&quot; data structure, built by process_database</span>
        <span class="c1"># key is a photo UUID, value is a dictionary with all the information</span>
        <span class="c1"># known about a photo</span>
        <span class="c1"># this is built by joining data from multiple queries against the photos database</span>
        <span class="c1"># several of the keys in the info dictionary point to other data structures described below</span>
        <span class="c1"># e.g. self._dbphotos[uuid][&quot;keywords&quot;] = self._dbkeywords_uuid[uuid]</span>
        <span class="c1">#      self._dbphotos[uuid][&quot;persons&quot;] = self._dbfaces_uuid[uuid]</span>
        <span class="c1">#      self._dbphotos[uuid][&quot;albums&quot;] = self._dbalbums_uuid[uuid]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about all burst photos by burst uuid</span>
        <span class="c1"># key is UUID of the burst set, value is a set of photo UUIDs in the burst set</span>
        <span class="c1"># e.g. {&#39;BD94B7C0-2EB8-43DB-98B4-3B8E9653C255&#39;: {&#39;8B386814-CA8A-42AA-BCA8-97C1AA746D8A&#39;, &#39;52B95550-DE4A-44DD-9E67-89E979F2E97F&#39;}}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_burst</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with additional information from RKMaster</span>
        <span class="c1"># key is UUID from RKMaster, value is dict with info related to each master</span>
        <span class="c1"># currently used to get information on RAW images</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_master</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about all persons by person PK</span>
        <span class="c1"># key is person PK, value is dict with info about each person</span>
        <span class="c1"># e.g. {3: {&quot;pk&quot;: 3, &quot;fullname&quot;: &quot;Maria Smith&quot;...}}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about all persons by person fullname</span>
        <span class="c1"># key is person PK, value is list of person PKs with fullname</span>
        <span class="c1"># there may be more than one person PK with the same fullname</span>
        <span class="c1"># e.g. {&quot;Maria Smith&quot;: [1, 2]}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_fullname</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about all persons/photos by uuid</span>
        <span class="c1"># key is photo UUID, value is list of person primary keys of persons in the photo</span>
        <span class="c1"># Note: Photos 5 identifies faces even if not given a name</span>
        <span class="c1"># and those are labeled by process_database as _UNKNOWN_</span>
        <span class="c1"># e.g. {&#39;1EB2B765-0765-43BA-A90C-0D0580E6172C&#39;: [1, 3, 5]}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about detected faces by person primary key</span>
        <span class="c1"># key is person pk, value is list of photo UUIDs</span>
        <span class="c1"># e.g. {3: [&#39;E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51&#39;]}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about all keywords/photos by uuid</span>
        <span class="c1"># key is photo uuid and value is list of keywords</span>
        <span class="c1"># e.g.  {&#39;1EB2B765-0765-43BA-A90C-0D0580E6172C&#39;: [&#39;Kids&#39;]}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about all keywords/photos by keyword</span>
        <span class="c1"># key is keyword and value is list of photo UUIDs that have that keyword</span>
        <span class="c1"># e.g. {&#39;England&#39;: [&#39;DC99FBDD-7A52-4100-A5BB-344131646C30&#39;]}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about all albums/photos by uuid</span>
        <span class="c1"># key is photo UUID, value is list of album UUIDs the photo is contained in</span>
        <span class="c1"># e.g.  {&#39;1EB2B765-0765-43BA-A90C-0D0580E6172C&#39;: [&#39;0C514A98-7B77-4E4F-801B-364B7B65EAFA&#39;]}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about all albums/photos by primary key in the album database</span>
        <span class="c1"># key is album pk, value is album uuid</span>
        <span class="c1"># e.g.  {&#39;43&#39;: &#39;0C514A98-7B77-4E4F-801B-364B7B65EAFA&#39;}</span>
        <span class="c1"># specific to Photos versions &gt;= 5</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_pk</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about all albums/photos by album</span>
        <span class="c1"># key is album UUID, value is list of tuples of (photo UUID, sort order) contained in that album</span>
        <span class="c1"># e.g. {&#39;0C514A98-7B77-4E4F-801B-364B7B65EAFA&#39;: [(&#39;1EB2B765-0765-43BA-A90C-0D0580E6172C&#39;, 1024)]}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about album details</span>
        <span class="c1"># key is album UUID, value is a dict with some additional details</span>
        <span class="c1"># (mostly about cloud status) of the album</span>
        <span class="c1"># e.g.  {&#39;0C514A98-7B77-4E4F-801B-364B7B65EAFA&#39;: {&#39;cloudidentifier&#39;: None,</span>
        <span class="c1">#       &#39;cloudlibrarystate&#39;: None, &#39;cloudlocalstate&#39;: 0, &#39;cloudownderlastname&#39;: None,</span>
        <span class="c1">#       &#39;cloudownerfirstname&#39;: None, &#39;cloudownerhashedpersonid&#39;: None, &#39;title&#39;: &#39;Pumpkin Farm&#39;}}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about album titles</span>
        <span class="c1"># key is title of album, value is list of album UUIDs with that title</span>
        <span class="c1"># (It&#39;s possible to have more than one album with the same title)</span>
        <span class="c1"># e.g. {&#39;Pumpkin Farm&#39;: [&#39;0C514A98-7B77-4E4F-801B-364B7B65EAFA&#39;]}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_titles</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about all the file system volumes/photos by uuid</span>
        <span class="c1"># key is volume UUID, value is name of file system volume</span>
        <span class="c1"># e.g. {&#39;8A0B2944-7B09-4D06-9AC3-4B0BF3F363F1&#39;: &#39;MacBook Mojave&#39;}</span>
        <span class="c1"># Used to find path of photos imported but not copied to the Photos library</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbvolumes</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about parent folders for folders and albums</span>
        <span class="c1"># key is album or folder UUID and value is list of UUIDs of parent folder</span>
        <span class="c1"># e.g. {&#39;0C514A98-7B77-4E4F-801B-364B7B65EAFA&#39;: [&#39;92D68107-B6C7-453B-96D2-97B0F26D5B8B&#39;],}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_parent_folders</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about folder hierarchy for each album / folder</span>
        <span class="c1"># key is uuid of album / folder, value is dict with uuid of descendant folder / album</span>
        <span class="c1"># structure is recursive as a descendant may itself have descendants</span>
        <span class="c1"># e.g. {&#39;AA4145F5-098C-496E-9197-B7584958FF9B&#39;: {&#39;99D24D3E-59E7-465F-B386-A48A94B00BC1&#39;: {&#39;F2246D82-1A12-4994-9654-3DC6FE38A7A8&#39;: None}}, }</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict with information about folders</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbfolder_details</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Will hold the primary key of root folder</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_folder_root_pk</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="c1"># Dict to hold signatures for finding possible duplicates</span>
        <span class="c1"># key is tuple of (original_filesize, date) and value is list of uuids that match that signature</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_signatures</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict to hold information on volume names (Photos 5+)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_filesystem_volumes</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict to hold information on moments (Photos 5+)</span>
        <span class="c1"># key is Z_PK of ZMOMENT table and values are the moment info</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_moment_pk</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict to hold data on imports for Photos &lt;= 4</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_import_group</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Dict to hold syndication info for Photos &gt;= 7</span>
        <span class="c1"># key is UUID and value is dict of syndication info</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_syndication_uuid</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_find_database</span><span class="p">(</span><span class="n">dbfile</span><span class="p">,</span> <span class="n">library_path</span><span class="p">)</span>

        <span class="k">if</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="nb">int</span><span class="p">(</span><span class="n">_PHOTOS_4_VERSION</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_process_database4</span><span class="p">()</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_process_database5</span><span class="p">()</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_db_connection</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_db_connection</span><span class="p">()</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_source</span> <span class="o">=</span> <span class="s2">&quot;Photos&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_find_database</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dbfile</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span> <span class="n">library_path</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Find the right Photos database file and initialize internal variables for&quot;&quot;&quot;</span>

        <span class="c1"># This function is overly complex and a bit of a mess due to the way osxphotos evolved</span>
        <span class="c1"># osxphotos was originally designed to work with only Photos legacy (&lt;Photos 5) databases so all data was in photos.db</span>
        <span class="c1"># Photos 5 introduced a new database format (Photos.sqlite) and a new library structure</span>
        <span class="c1"># so this method attempts to find the right database file and also deal with situations where</span>
        <span class="c1"># there is an exclusive lock on the database file by creating a read-only copy if necessary</span>
        <span class="c1"># I apologize in advance if you need to work on this code!</span>

        <span class="c1"># the database could be a library path (&quot;/Users/user/Pictures/Photos Library.photoslibrary&quot;)</span>
        <span class="c1"># or a pre-Photos 5 database file (photos.db) or a post-Photos 5 database file (Photos.sqlite)</span>
        <span class="c1"># check for the right version and determine what version of Photos the database is from</span>

        <span class="n">verbose</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_verbose</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;dbfile = </span><span class="si">{</span><span class="n">dbfile</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">dbfile</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">dbfile</span> <span class="o">=</span> <span class="n">get_last_library_path</span><span class="p">()</span>
            <span class="k">if</span> <span class="n">dbfile</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
                <span class="c1"># get_last_library_path must have failed to find library</span>
                <span class="k">raise</span> <span class="ne">FileNotFoundError</span><span class="p">(</span><span class="s2">&quot;Could not get path to photo library database&quot;</span><span class="p">)</span>

        <span class="n">dbfile</span><span class="p">:</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">dbfile</span><span class="p">)</span>
        <span class="n">dbfile</span> <span class="o">=</span> <span class="n">dbfile</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span>
        <span class="n">photos_5</span> <span class="o">=</span> <span class="kc">False</span>
        <span class="k">if</span> <span class="n">dbfile</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
            <span class="c1"># passed a directory, assume it&#39;s a photoslibrary</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dbfile</span> <span class="o">/</span> <span class="s2">&quot;database&quot;</span> <span class="o">/</span> <span class="s2">&quot;Photos.sqlite&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
                <span class="c1"># Photos 5+ file</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span> <span class="o">=</span> <span class="n">dbfile</span> <span class="o">/</span> <span class="s2">&quot;database&quot;</span> <span class="o">/</span> <span class="s2">&quot;Photos.sqlite&quot;</span>
                <span class="n">photos_5</span> <span class="o">=</span> <span class="kc">True</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dbfile</span> <span class="o">/</span> <span class="s2">&quot;database&quot;</span> <span class="o">/</span> <span class="s2">&quot;photos.db&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_file</span> <span class="o">=</span> <span class="n">dbfile</span> <span class="o">/</span> <span class="s2">&quot;database&quot;</span> <span class="o">/</span> <span class="s2">&quot;photos.db&quot;</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="n">photos_5</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_file</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span><span class="p">:</span>
                <span class="k">raise</span> <span class="ne">FileNotFoundError</span><span class="p">(</span>
                    <span class="sa">f</span><span class="s2">&quot;Could not find Photos database file in </span><span class="si">{</span><span class="n">dbfile</span><span class="si">}</span><span class="s2">&quot;</span>
                <span class="p">)</span>
        <span class="k">elif</span> <span class="ow">not</span> <span class="n">dbfile</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="c1"># passed a non-existent file</span>
            <span class="k">raise</span> <span class="ne">FileNotFoundError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;dbfile </span><span class="si">{</span><span class="n">dbfile</span><span class="si">}</span><span class="s2"> does not exist&quot;</span><span class="p">,</span> <span class="n">dbfile</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">dbfile</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">&quot;photos.db&quot;</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span> <span class="o">=</span> <span class="n">dbfile</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span> <span class="o">=</span> <span class="n">dbfile</span>
            <span class="c1"># check to see if Photos.sqlite exists in same folder</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dbfile</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s2">&quot;Photos.sqlite&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
                <span class="c1"># Photos 5+ file</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span> <span class="o">=</span> <span class="n">dbfile</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s2">&quot;Photos.sqlite&quot;</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># assume it was a Photos.sqlite file passed</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span> <span class="o">=</span> <span class="n">dbfile</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dbfile</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s2">&quot;photos.db&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
                <span class="c1"># photos.db should be in same folder as Photos.sqlite</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span> <span class="o">=</span> <span class="n">dbfile</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="s2">&quot;photos.db&quot;</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span> <span class="o">=</span> <span class="n">dbfile</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span>

        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="si">=}</span><span class="s2"> </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span><span class="si">=}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="c1"># _tmp_db is the file that will processed by _process_database4/5</span>
        <span class="c1"># assume _tmp_db will be _dbfile or _dbfile_actual based on Photos version</span>
        <span class="c1"># unless DB is locked, in which case _tmp_db will point to a temporary copy</span>
        <span class="c1"># if Photos &lt;=4, _dbfile = _dbfile_actual = photos.db</span>
        <span class="c1"># if Photos &gt;= 5, _dbfile = photos.db, from which we get DB version but the actual</span>
        <span class="c1"># photos data is in Photos.sqlite</span>
        <span class="c1"># In either case, a temporary copy will be made if the DB is locked by Photos</span>
        <span class="c1"># or photosanalysisd</span>

        <span class="c1"># if database is exclusively locked, make a copy of it and use the copy</span>
        <span class="c1"># Photos maintains an exclusive lock on the database file while Photos is open</span>
        <span class="c1"># photoanalysisd sometimes maintains this lock even after Photos is closed</span>
        <span class="c1"># In those cases, make a temp copy of the file for sqlite3 to read</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span>

        <span class="c1"># _db_version is set from photos.db</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">:</span>
            <span class="n">verbose</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Processing database </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">sqlite_db_is_locked</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">):</span>
                    <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;photos.db locked, creating temporary copy.&quot;</span><span class="p">)</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_copy_db_file</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">=</span> <span class="n">get_db_version</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
                <span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
                    <span class="sa">f</span><span class="s2">&quot;Error getting database version from </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span>
                <span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">=</span> <span class="s2">&quot;6000&quot;</span>  <span class="c1"># assume Photos 5+ and hope for the best</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="si">=}</span><span class="s2">, setting _db_version to 6000&quot;</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">=</span> <span class="s2">&quot;6000&quot;</span>

        <span class="c1"># _photos_version is set from Photos.sqlite which only exists for Photos 5+</span>
        <span class="n">db_ver_int</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">db_ver_int</span> <span class="o">&lt;</span> <span class="mi">3000</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">=</span> <span class="mi">2</span>
        <span class="k">elif</span> <span class="n">db_ver_int</span> <span class="o">&lt;</span> <span class="mi">4000</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">=</span> <span class="mi">3</span>
        <span class="k">elif</span> <span class="n">db_ver_int</span> <span class="o">&lt;</span> <span class="mi">5000</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">=</span> <span class="mi">4</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">=</span> <span class="mi">5</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_model_ver</span> <span class="o">=</span> <span class="mi">0</span>  <span class="c1"># only set for Photos 5+</span>

        <span class="c1"># If Photos &gt;= 5, actual data isn&#39;t in photos.db but in Photos.sqlite</span>
        <span class="k">if</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span><span class="p">)</span> <span class="o">&gt;</span> <span class="nb">int</span><span class="p">(</span><span class="n">_PHOTOS_4_VERSION</span><span class="p">):</span>
            <span class="n">verbose</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Processing database </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_filepath</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
            <span class="c1"># if database is exclusively locked, make a copy of it and use the copy</span>
            <span class="k">if</span> <span class="n">sqlite_db_is_locked</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span><span class="p">):</span>
                <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Database locked, creating temporary copy.&quot;</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_copy_db_file</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span>
            <span class="c1"># set the photos version to actual value based on Photos.sqlite</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">=</span> <span class="n">get_photos_version_from_model</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_model_ver</span> <span class="o">=</span> <span class="n">get_model_version</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span><span class="p">)</span>

            <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
                <span class="sa">f</span><span class="s2">&quot;_dbfile = </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="si">}</span><span class="s2">, _dbfile_actual = </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span><span class="si">}</span><span class="s2">&quot;</span>
            <span class="p">)</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">library_path</span><span class="p">:</span>
            <span class="c1"># library_path not provided as argument (this is the normal case)</span>
            <span class="c1"># determine library path relative to the database path</span>
            <span class="n">library_path</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">parent</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">library_path</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">library_path</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_library_path</span> <span class="o">=</span> <span class="n">library_path</span>
        <span class="k">if</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="nb">int</span><span class="p">(</span><span class="n">_PHOTOS_4_VERSION</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_masters_path</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_library_path</span> <span class="o">/</span> <span class="s2">&quot;Masters&quot;</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_masters_path</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_library_path</span> <span class="o">/</span> <span class="s2">&quot;originals&quot;</span>

        <span class="c1"># legacy code expects all paths to be str so convert to str</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_library_path</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_library_path</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_masters_path</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_masters_path</span><span class="p">)</span>

        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_library_path</span><span class="si">=}</span><span class="s2">,</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_masters_path</span><span class="si">=}</span><span class="s2">&quot;</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">keywords_as_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return keywords as dict of keyword: count in reverse sorted order (descending)&quot;&quot;&quot;</span>
        <span class="n">keywords</span> <span class="o">=</span> <span class="p">{</span>
            <span class="n">k</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">k</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
        <span class="p">}</span>
        <span class="n">keywords</span> <span class="o">|=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="mi">0</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">keywords_without_photo</span><span class="p">}</span>
        <span class="n">keywords</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">keywords</span><span class="o">.</span><span class="n">items</span><span class="p">(),</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">kv</span><span class="p">:</span> <span class="n">kv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">keywords</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">keywords_without_photo</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return keywords that exist in the database but are not assined to any photo (Photos 5+ only)&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">&lt;=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
            <span class="c1"># not implemented for Photos &lt;= 4</span>
            <span class="k">return</span> <span class="p">{}</span>

        <span class="n">results</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;SELECT ZTITLE FROM ZKEYWORD&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="n">keywords</span> <span class="o">=</span> <span class="p">[</span><span class="n">normalize_unicode</span><span class="p">(</span><span class="n">r</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">results</span><span class="p">]</span>
        <span class="n">no_photo_keywords</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">kw</span> <span class="ow">in</span> <span class="n">keywords</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">kw</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">:</span>
                <span class="n">no_photo_keywords</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">kw</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">no_photo_keywords</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">persons_as_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return persons as dict of person, count in reverse sorted order (descending)&quot;&quot;&quot;</span>
        <span class="n">persons</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="k">for</span> <span class="n">pk</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">:</span>
            <span class="n">fullname</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">][</span><span class="s2">&quot;fullname&quot;</span><span class="p">]</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">persons</span><span class="p">[</span><span class="n">fullname</span><span class="p">]</span> <span class="o">+=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">])</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="n">persons</span><span class="p">[</span><span class="n">fullname</span><span class="p">]</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">])</span>
        <span class="n">persons</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">persons</span><span class="o">.</span><span class="n">items</span><span class="p">(),</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">kv</span><span class="p">:</span> <span class="n">kv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">persons</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">albums_as_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return albums as dict of albums, count in reverse sorted order (descending)&quot;&quot;&quot;</span>
        <span class="n">albums</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="n">album_keys</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_album_uuids</span><span class="p">(</span><span class="n">shared</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">album_keys</span><span class="p">:</span>
            <span class="n">title</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">[</span><span class="n">album</span><span class="p">][</span><span class="s2">&quot;title&quot;</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">album</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">:</span>
                <span class="k">try</span><span class="p">:</span>
                    <span class="n">albums</span><span class="p">[</span><span class="n">title</span><span class="p">]</span> <span class="o">+=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">[</span><span class="n">album</span><span class="p">])</span>
                <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                    <span class="n">albums</span><span class="p">[</span><span class="n">title</span><span class="p">]</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">[</span><span class="n">album</span><span class="p">])</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">albums</span><span class="p">[</span><span class="n">title</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>  <span class="c1"># empty album</span>
        <span class="n">albums</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">albums</span><span class="o">.</span><span class="n">items</span><span class="p">(),</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">kv</span><span class="p">:</span> <span class="n">kv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">albums</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">albums_shared_as_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns shared albums as dict of albums, count in reverse sorted order (descending)</span>
<span class="sd">        valid only on Photos 5; on Photos &lt;= 4, prints warning and returns empty dict&quot;&quot;&quot;</span>

        <span class="n">albums</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="n">album_keys</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_album_uuids</span><span class="p">(</span><span class="n">shared</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">album_keys</span><span class="p">:</span>
            <span class="n">title</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">[</span><span class="n">album</span><span class="p">][</span><span class="s2">&quot;title&quot;</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">album</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">:</span>
                <span class="k">try</span><span class="p">:</span>
                    <span class="n">albums</span><span class="p">[</span><span class="n">title</span><span class="p">]</span> <span class="o">+=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">[</span><span class="n">album</span><span class="p">])</span>
                <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                    <span class="n">albums</span><span class="p">[</span><span class="n">title</span><span class="p">]</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">[</span><span class="n">album</span><span class="p">])</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">albums</span><span class="p">[</span><span class="n">title</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>  <span class="c1"># empty album</span>
        <span class="n">albums</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">albums</span><span class="o">.</span><span class="n">items</span><span class="p">(),</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">kv</span><span class="p">:</span> <span class="n">kv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">albums</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">keywords</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of keywords found in photos database and associated with at least one photo&quot;&quot;&quot;</span>
        <span class="n">keywords</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
        <span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">keywords</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">persons</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of persons found in photos database and associated with at least one photo&quot;&quot;&quot;</span>
        <span class="n">persons</span> <span class="o">=</span> <span class="p">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;fullname&quot;</span><span class="p">]</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">}</span>
        <span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">persons</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">person_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of PersonInfo objects for each person in the photos database&quot;&quot;&quot;</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_person_info</span>
        <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_person_info</span> <span class="o">=</span> <span class="p">[</span>
                <span class="n">PersonInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">pk</span><span class="o">=</span><span class="n">pk</span><span class="p">)</span> <span class="k">for</span> <span class="n">pk</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span>
            <span class="p">]</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_person_info</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">folder_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list FolderInfo objects representing top-level folders in the photos database&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">&lt;=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
            <span class="n">folders</span> <span class="o">=</span> <span class="p">[</span>
                <span class="n">FolderInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">folder</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">folder</span><span class="p">,</span> <span class="n">detail</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfolder_details</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;intrash&quot;</span><span class="p">]</span>
                <span class="ow">and</span> <span class="ow">not</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;isMagic&quot;</span><span class="p">]</span>
                <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;parentFolderUuid&quot;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">_PHOTOS_4_TOP_LEVEL_ALBUMS</span>
            <span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">folders</span> <span class="o">=</span> <span class="p">[</span>
                <span class="n">FolderInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">album</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">album</span><span class="p">,</span> <span class="n">detail</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;intrash&quot;</span><span class="p">]</span>
                <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;kind&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">_PHOTOS_5_FOLDER_KIND</span>
                <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;parentfolder&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">_folder_root_pk</span>
            <span class="p">]</span>
        <span class="k">return</span> <span class="n">folders</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">folders</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of top-level folder names in the photos database&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">&lt;=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
            <span class="n">folder_names</span> <span class="o">=</span> <span class="p">[</span>
                <span class="n">folder</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>
                <span class="k">for</span> <span class="n">folder</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfolder_details</span><span class="o">.</span><span class="n">values</span><span class="p">()</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="n">folder</span><span class="p">[</span><span class="s2">&quot;intrash&quot;</span><span class="p">]</span>
                <span class="ow">and</span> <span class="ow">not</span> <span class="n">folder</span><span class="p">[</span><span class="s2">&quot;isMagic&quot;</span><span class="p">]</span>
                <span class="ow">and</span> <span class="n">folder</span><span class="p">[</span><span class="s2">&quot;parentFolderUuid&quot;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">_PHOTOS_4_TOP_LEVEL_ALBUMS</span>
            <span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">folder_names</span> <span class="o">=</span> <span class="p">[</span>
                <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;title&quot;</span><span class="p">]</span>
                <span class="k">for</span> <span class="n">detail</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="o">.</span><span class="n">values</span><span class="p">()</span>
                <span class="k">if</span> <span class="ow">not</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;intrash&quot;</span><span class="p">]</span>
                <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;kind&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">_PHOTOS_5_FOLDER_KIND</span>
                <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;parentfolder&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">_folder_root_pk</span>
            <span class="p">]</span>
        <span class="k">return</span> <span class="n">folder_names</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">album_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of AlbumInfo objects for each album in the photos database&quot;&quot;&quot;</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album_info</span>
        <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_album_info</span> <span class="o">=</span> <span class="p">[</span>
                <span class="n">AlbumInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">album</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_album_uuids</span><span class="p">(</span><span class="n">shared</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
            <span class="p">]</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album_info</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">album_info_shared</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of AlbumInfo objects for each shared album in the photos database</span>
<span class="sd">        only valid for Photos 5; on Photos &lt;= 4, prints warning and returns empty list</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="c1"># if _dbalbum_details[key][&quot;cloudownerhashedpersonid&quot;] is not None, then it&#39;s a shared album</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album_info_shared</span>
        <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_album_info_shared</span> <span class="o">=</span> <span class="p">[</span>
                <span class="n">AlbumInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">album</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_album_uuids</span><span class="p">(</span><span class="n">shared</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
            <span class="p">]</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album_info_shared</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">albums</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of albums found in photos database&quot;&quot;&quot;</span>

        <span class="c1"># Could be more than one album with same name</span>
        <span class="c1"># Right now, they are treated as same album and photos are combined from albums with same name</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_albums</span>
        <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_albums</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_albums</span><span class="p">(</span><span class="n">shared</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_albums</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">albums_shared</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of shared albums found in photos database</span>
<span class="sd">        only valid for Photos 5; on Photos &lt;= 4, prints warning and returns empty list</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># Could be more than one album with same name</span>
        <span class="c1"># Right now, they are treated as same album and photos are combined from albums with same name</span>

        <span class="c1"># if _dbalbum_details[key][&quot;cloudownerhashedpersonid&quot;] is not None, then it&#39;s a shared album</span>

        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_albums_shared</span>
        <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_albums_shared</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_albums</span><span class="p">(</span><span class="n">shared</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_albums_shared</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">import_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of ImportInfo objects for each import session in the database&quot;&quot;&quot;</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_import_info</span>
        <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_import_info</span> <span class="o">=</span> <span class="p">[</span>
                <span class="n">ImportInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">album</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_album_uuids</span><span class="p">(</span><span class="n">import_session</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
            <span class="p">]</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_import_info</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">project_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of AlbumInfo projects for each project in the database&quot;&quot;&quot;</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_project_info</span>
        <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_project_info</span> <span class="o">=</span> <span class="p">[</span>
                <span class="n">ProjectInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">album</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_album_uuids</span><span class="p">(</span><span class="n">project</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
            <span class="p">]</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_project_info</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">db_version</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the Photos database version&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">db_path</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns path to the Photos library database&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfile_actual</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">library_path</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns path to the Photos library&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_library_path</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">photos_version</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns version of Photos app that created the library&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span>

<div class="viewcode-block" id="PhotosDB.get_db_connection">
<a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB.get_db_connection">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_db_connection</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Get connection to the working copy of the Photos database</span>

<span class="sd">        Returns:</span>
<span class="sd">            tuple of (connection, cursor) to sqlite3 database</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">sqlite_open_ro</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span><span class="p">)</span></div>


    <span class="k">def</span><span class="w"> </span><span class="nf">_copy_db_file</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fname</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;copies the sqlite database file to a temp file&quot;&quot;&quot;</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot; returns the name of the temp file &quot;&quot;&quot;</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot; If sqlite shared memory and write-ahead log files exist, those are copied too &quot;&quot;&quot;</span>
        <span class="c1"># required because python&#39;s sqlite3 implementation can&#39;t read a locked file</span>
        <span class="c1"># _, suffix = os.path.splitext(fname)</span>
        <span class="n">dest_name</span> <span class="o">=</span> <span class="n">dest_path</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">dest_name</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">fname</span><span class="p">)</span><span class="o">.</span><span class="n">name</span>
            <span class="n">dest_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tempdir_name</span><span class="p">,</span> <span class="n">dest_name</span><span class="p">)</span>
            <span class="n">FileUtil</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="n">fname</span><span class="p">,</span> <span class="n">dest_path</span><span class="p">)</span>
            <span class="c1"># copy write-ahead log and shared memory files (-wal and -shm) files if they exist</span>
            <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">fname</span><span class="si">}</span><span class="s2">-wal&quot;</span><span class="p">):</span>
                <span class="n">FileUtil</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">fname</span><span class="si">}</span><span class="s2">-wal&quot;</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">dest_path</span><span class="si">}</span><span class="s2">-wal&quot;</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">fname</span><span class="si">}</span><span class="s2">-shm&quot;</span><span class="p">):</span>
                <span class="n">FileUtil</span><span class="o">.</span><span class="n">copy</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">fname</span><span class="si">}</span><span class="s2">-shm&quot;</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">dest_path</span><span class="si">}</span><span class="s2">-shm&quot;</span><span class="p">)</span>
        <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error copying</span><span class="si">{</span><span class="n">fname</span><span class="si">}</span><span class="s2"> to </span><span class="si">{</span><span class="n">dest_path</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span> <span class="kn">from</span><span class="w"> </span><span class="nn">e</span>

        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">dest_path</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">dest_path</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_process_database4</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;process the Photos database to extract info</span>
<span class="sd">        works on Photos version &lt;= 4.0&quot;&quot;&quot;</span>

        <span class="n">verbose</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_verbose</span>
        <span class="n">verbose</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Photos database version: </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_num</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span><span class="p">)</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>

        <span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span> <span class="o">=</span> <span class="n">sqlite_open_ro</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span><span class="p">)</span>

        <span class="c1"># get info to associate persons with photos</span>
        <span class="c1"># then get detected faces in each photo and link to persons</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing persons in photos.&quot;</span><span class="p">)</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT</span>
<span class="sd">                RKPerson.modelID,</span>
<span class="sd">                RKPerson.uuid,</span>
<span class="sd">                RKPerson.name,</span>
<span class="sd">                RKPerson.faceCount,</span>
<span class="sd">                RKPerson.displayName,</span>
<span class="sd">                RKPerson.representativeFaceId</span>
<span class="sd">                FROM RKPerson</span>
<span class="sd">            &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># 0     RKPerson.modelID,</span>
        <span class="c1"># 1     RKPerson.uuid,</span>
        <span class="c1"># 2     RKPerson.name,</span>
        <span class="c1"># 3     RKPerson.faceCount,</span>
        <span class="c1"># 4     RKPerson.displayName</span>
        <span class="c1"># 5     RKPerson.representativeFaceId</span>

        <span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">pk</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">fullname</span> <span class="o">=</span> <span class="p">(</span>
                <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
                <span class="k">if</span> <span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
                <span class="k">else</span> <span class="n">_UNKNOWN_PERSON</span>
            <span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
                <span class="s2">&quot;pk&quot;</span><span class="p">:</span> <span class="n">pk</span><span class="p">,</span>
                <span class="s2">&quot;uuid&quot;</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
                <span class="s2">&quot;fullname&quot;</span><span class="p">:</span> <span class="n">fullname</span><span class="p">,</span>
                <span class="s2">&quot;facecount&quot;</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span>
                <span class="s2">&quot;keyface&quot;</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">5</span><span class="p">],</span>
                <span class="s2">&quot;displayname&quot;</span><span class="p">:</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">person</span><span class="p">[</span><span class="mi">4</span><span class="p">]),</span>
                <span class="s2">&quot;photo_uuid&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
                <span class="s2">&quot;keyface_uuid&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
                <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>  <span class="c1"># Photos 5+</span>
                <span class="s2">&quot;manualorder&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>  <span class="c1"># Photos 5+</span>
            <span class="p">}</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_fullname</span><span class="p">[</span><span class="n">fullname</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">pk</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_fullname</span><span class="p">[</span><span class="n">fullname</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">pk</span><span class="p">]</span>

        <span class="c1"># get info on key face</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT</span>
<span class="sd">                RKPerson.modelID,</span>
<span class="sd">                RKPerson.representativeFaceId,</span>
<span class="sd">                RKVersion.uuid,</span>
<span class="sd">                RKFace.uuid</span>
<span class="sd">                FROM RKPerson, RKFace, RKVersion</span>
<span class="sd">                WHERE</span>
<span class="sd">                RKFace.modelId = RKPerson.representativeFaceId AND</span>
<span class="sd">                RKVersion.modelId = RKFace.ImageModelId</span>
<span class="sd">            &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># 0     RKPerson.modelID,</span>
        <span class="c1"># 1     RKPerson.representativeFaceId</span>
        <span class="c1"># 2     RKVersion.uuid,</span>
        <span class="c1"># 3     RKFace.uuid</span>

        <span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">pk</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">][</span><span class="s2">&quot;photo_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">][</span><span class="s2">&quot;keyface_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unexpected KeyError _dbpersons_pk[</span><span class="si">{</span><span class="n">pk</span><span class="si">}</span><span class="s2">]&quot;</span><span class="p">)</span>

        <span class="c1"># get information on detected faces</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing detected faces in photos.&quot;</span><span class="p">)</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT</span>
<span class="sd">                RKPerson.modelID,</span>
<span class="sd">                RKVersion.uuid</span>
<span class="sd">                FROM</span>
<span class="sd">                RKFace, RKPerson, RKVersion, RKMaster</span>
<span class="sd">                WHERE</span>
<span class="sd">                RKFace.personID = RKperson.modelID AND</span>
<span class="sd">                RKVersion.modelId = RKFace.ImageModelId AND</span>
<span class="sd">                RKVersion.masterUuid = RKMaster.uuid</span>
<span class="sd">            &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># 0     RKPerson.modelID</span>
        <span class="c1"># 1     RKVersion.uuid</span>

        <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">pk</span> <span class="o">=</span> <span class="n">face</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">face</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">pk</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">pk</span><span class="p">]</span>

            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">uuid</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">uuid</span><span class="p">]</span>

        <span class="c1"># Get info on albums</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing albums.&quot;</span><span class="p">)</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT</span>
<span class="sd">                RKAlbum.uuid,</span>
<span class="sd">                RKVersion.uuid,</span>
<span class="sd">                RKCustomSortOrder.orderNumber</span>
<span class="sd">                FROM RKVersion</span>
<span class="sd">                JOIN RKCustomSortOrder on RKCustomSortOrder.objectUuid = RKVersion.uuid</span>
<span class="sd">                JOIN RKAlbum on RKAlbum.uuid = RKCustomSortOrder.containerUuid</span>
<span class="sd">            &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># 0     RKAlbum.uuid,</span>
        <span class="c1"># 1     RKVersion.uuid,</span>
        <span class="c1"># 2     RKCustomSortOrder.orderNumber</span>

        <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="c1"># store by uuid in _dbalbums_uuid and by album in _dbalbums_album</span>
            <span class="n">album_uuid</span> <span class="o">=</span> <span class="n">album</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">photo_uuid</span> <span class="o">=</span> <span class="n">album</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
            <span class="n">sort_order</span> <span class="o">=</span> <span class="n">album</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span><span class="p">[</span><span class="n">photo_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">album_uuid</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span><span class="p">[</span><span class="n">photo_uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span>

            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">photo_uuid</span><span class="p">,</span> <span class="n">sort_order</span><span class="p">))</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">[(</span><span class="n">photo_uuid</span><span class="p">,</span> <span class="n">sort_order</span><span class="p">)]</span>

        <span class="c1"># now get additional details about albums</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT</span>
<span class="sd">                uuid,</span>
<span class="sd">                name,</span>
<span class="sd">                cloudLibraryState,</span>
<span class="sd">                cloudIdentifier,</span>
<span class="sd">                isInTrash,</span>
<span class="sd">                folderUuid,</span>
<span class="sd">                albumType,</span>
<span class="sd">                albumSubclass,</span>
<span class="sd">                createDate</span>
<span class="sd">                FROM RKAlbum &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># Order of results</span>
        <span class="c1"># 0:    uuid</span>
        <span class="c1"># 1:    name</span>
        <span class="c1"># 2:    cloudLibraryState</span>
        <span class="c1"># 3:    cloudIdentifier</span>
        <span class="c1"># 4:    isInTrash</span>
        <span class="c1"># 5:    folderUuid</span>
        <span class="c1"># 6:    albumType</span>
        <span class="c1"># 7:    albumSubclass -- if 3, normal user album</span>
        <span class="c1"># 8:    createDate</span>

        <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">[</span><span class="n">album</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{</span>
                <span class="s2">&quot;_uuid&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
                <span class="s2">&quot;title&quot;</span><span class="p">:</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">album</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span>
                <span class="s2">&quot;cloudlibrarystate&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span>
                <span class="s2">&quot;cloudidentifier&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span>
                <span class="s2">&quot;intrash&quot;</span><span class="p">:</span> <span class="kc">False</span> <span class="k">if</span> <span class="n">album</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="kc">True</span><span class="p">,</span>
                <span class="s2">&quot;cloudlocalstate&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>  <span class="c1"># Photos 5+</span>
                <span class="s2">&quot;cloudownerfirstname&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>  <span class="c1"># Photos 5+</span>
                <span class="s2">&quot;cloudownderlastname&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>  <span class="c1"># Photos 5+</span>
                <span class="s2">&quot;cloudownerhashedpersonid&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>  <span class="c1"># Photos 5+</span>
                <span class="s2">&quot;folderUuid&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">5</span><span class="p">],</span>
                <span class="s2">&quot;albumType&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">6</span><span class="p">],</span>
                <span class="s2">&quot;albumSubclass&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">7</span><span class="p">],</span>
                <span class="c1"># for compatability with Photos 5 where album kind is ZKIND</span>
                <span class="s2">&quot;kind&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">7</span><span class="p">],</span>
                <span class="s2">&quot;creation_date&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">8</span><span class="p">],</span>
                <span class="s2">&quot;start_date&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>  <span class="c1"># Photos 5+ only</span>
                <span class="s2">&quot;end_date&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>  <span class="c1"># Photos 5+ only</span>
                <span class="s2">&quot;customsortascending&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>  <span class="c1"># Photos 5+ only</span>
                <span class="s2">&quot;customsortkey&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>  <span class="c1"># Photos 5+ only</span>
            <span class="p">}</span>

        <span class="c1"># get details about folders</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT</span>
<span class="sd">                uuid,</span>
<span class="sd">                modelId,</span>
<span class="sd">                name,</span>
<span class="sd">                isMagic,</span>
<span class="sd">                isInTrash,</span>
<span class="sd">                folderType,</span>
<span class="sd">                parentFolderUuid,</span>
<span class="sd">                folderPath</span>
<span class="sd">                FROM RKFolder &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># Order of results</span>
        <span class="c1"># 0     uuid,</span>
        <span class="c1"># 1     modelId,</span>
        <span class="c1"># 2     name,</span>
        <span class="c1"># 3     isMagic,</span>
        <span class="c1"># 4     isInTrash,</span>
        <span class="c1"># 5     folderType,</span>
        <span class="c1"># 6     parentFolderUuid,</span>
        <span class="c1"># 7     folderPath</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbfolder_details</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
                <span class="s2">&quot;_uuid&quot;</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
                <span class="s2">&quot;modelId&quot;</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
                <span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]),</span>
                <span class="s2">&quot;isMagic&quot;</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span>
                <span class="s2">&quot;intrash&quot;</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span>
                <span class="s2">&quot;folderType&quot;</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="mi">5</span><span class="p">],</span>
                <span class="s2">&quot;parentFolderUuid&quot;</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="mi">6</span><span class="p">],</span>
                <span class="s2">&quot;folderPath&quot;</span><span class="p">:</span> <span class="n">row</span><span class="p">[</span><span class="mi">7</span><span class="p">],</span>
            <span class="p">}</span>

        <span class="c1"># build _dbalbum_folders in form uuid: [parent uuid] to be consistent with _process_database5</span>
        <span class="k">for</span> <span class="n">album</span><span class="p">,</span> <span class="n">details</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="c1"># album can be in a single folder</span>
            <span class="n">parent</span> <span class="o">=</span> <span class="n">details</span><span class="p">[</span><span class="s2">&quot;folderUuid&quot;</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_parent_folders</span><span class="p">[</span><span class="n">album</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">parent</span><span class="p">]</span>

        <span class="c1"># build folder hierarchy</span>
        <span class="k">for</span> <span class="n">album</span><span class="p">,</span> <span class="n">details</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="n">parent_folder</span> <span class="o">=</span> <span class="n">details</span><span class="p">[</span><span class="s2">&quot;folderUuid&quot;</span><span class="p">]</span>
            <span class="k">if</span> <span class="p">(</span>
                <span class="n">details</span><span class="p">[</span><span class="s2">&quot;albumSubclass&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">_PHOTOS_4_ALBUM_KIND</span>
                <span class="ow">and</span> <span class="n">parent_folder</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">_PHOTOS_4_TOP_LEVEL_ALBUMS</span>
            <span class="p">):</span>
                <span class="n">folder_hierarchy</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_build_album_folder_hierarchy_4</span><span class="p">(</span><span class="n">parent_folder</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album</span><span class="p">]</span> <span class="o">=</span> <span class="n">folder_hierarchy</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="c1"># Get info on keywords</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing keywords.&quot;</span><span class="p">)</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT</span>
<span class="sd">                RKKeyword.name,</span>
<span class="sd">                RKVersion.uuid,</span>
<span class="sd">                RKMaster.uuid</span>
<span class="sd">                FROM</span>
<span class="sd">                RKKeyword, RKKeywordForVersion, RKVersion, RKMaster</span>
<span class="sd">                WHERE</span>
<span class="sd">                RKKeyword.modelId = RKKeyWordForVersion.keywordID AND</span>
<span class="sd">                RKVersion.modelID = RKKeywordForVersion.versionID AND</span>
<span class="sd">                RKMaster.uuid = RKVersion.masterUuid</span>
<span class="sd">            &quot;&quot;&quot;</span>
        <span class="p">)</span>
        <span class="k">for</span> <span class="n">keyword_title</span><span class="p">,</span> <span class="n">keyword_uuid</span><span class="p">,</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">keyword_title</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">keyword_title</span><span class="p">)</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">keyword_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword_title</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">keyword_uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword_uuid</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">keyword_uuid</span><span class="p">]</span>

        <span class="c1"># Get info on disk volumes</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;select RKVolume.modelId, RKVolume.name from RKVolume&quot;</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">vol</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbvolumes</span><span class="p">[</span><span class="n">vol</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span> <span class="o">=</span> <span class="n">vol</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>

        <span class="c1"># Get photo details</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing photo details.&quot;</span><span class="p">)</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">&lt;</span> <span class="n">_PHOTOS_3_VERSION</span><span class="p">:</span>
            <span class="c1"># Photos &lt; 3.0 doesn&#39;t have RKVersion.selfPortrait (selfie)</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; SELECT RKVersion.uuid, RKVersion.modelId, RKVersion.masterUuid, RKVersion.filename,</span>
<span class="sd">                    RKVersion.lastmodifieddate, RKVersion.imageDate, RKVersion.mainRating,</span>
<span class="sd">                    RKVersion.hasAdjustments, RKVersion.hasKeywords, RKVersion.imageTimeZoneOffsetSeconds,</span>
<span class="sd">                    RKMaster.volumeId, RKMaster.imagePath, RKVersion.extendedDescription, RKVersion.name,</span>
<span class="sd">                    RKMaster.isMissing, RKMaster.originalFileName, RKVersion.isFavorite, RKVersion.isHidden,</span>
<span class="sd">                    RKVersion.latitude, RKVersion.longitude,</span>
<span class="sd">                    RKVersion.adjustmentUuid, RKVersion.type, RKMaster.UTI,</span>
<span class="sd">                    RKVersion.burstUuid, RKVersion.burstPickType,</span>
<span class="sd">                    RKVersion.specialType, RKMaster.modelID, null, RKVersion.momentUuid,</span>
<span class="sd">                    RKVersion.rawMasterUuid,</span>
<span class="sd">                    RKVersion.nonRawMasterUuid,</span>
<span class="sd">                    RKMaster.alternateMasterUuid,</span>
<span class="sd">                    RKVersion.isInTrash,</span>
<span class="sd">                    RKVersion.processedHeight,</span>
<span class="sd">                    RKVersion.processedWidth,</span>
<span class="sd">                    RKVersion.orientation,</span>
<span class="sd">                    RKMaster.height,</span>
<span class="sd">                    RKMaster.width,</span>
<span class="sd">                    RKMaster.orientation,</span>
<span class="sd">                    RKMaster.fileSize,</span>
<span class="sd">                    RKVersion.subType,</span>
<span class="sd">                    RKVersion.inTrashDate,</span>
<span class="sd">                    RKVersion.showInLibrary,</span>
<span class="sd">                    RKMaster.fileIsReference,</span>
<span class="sd">                    RKMaster.importGroupUuid,</span>
<span class="sd">                    RKMaster.fingerprint,</span>
<span class="sd">                    RKVersion.imageTimeZoneName</span>
<span class="sd">                    FROM RKVersion, RKMaster</span>
<span class="sd">                    WHERE RKVersion.masterUuid = RKMaster.uuid&quot;&quot;&quot;</span>
            <span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">                </span><span class="sd">&quot;&quot;&quot; SELECT RKVersion.uuid, RKVersion.modelId, RKVersion.masterUuid, RKVersion.filename,</span>
<span class="sd">                    RKVersion.lastmodifieddate, RKVersion.imageDate, RKVersion.mainRating,</span>
<span class="sd">                    RKVersion.hasAdjustments, RKVersion.hasKeywords, RKVersion.imageTimeZoneOffsetSeconds,</span>
<span class="sd">                    RKMaster.volumeId, RKMaster.imagePath, RKVersion.extendedDescription, RKVersion.name,</span>
<span class="sd">                    RKMaster.isMissing, RKMaster.originalFileName, RKVersion.isFavorite, RKVersion.isHidden,</span>
<span class="sd">                    RKVersion.latitude, RKVersion.longitude,</span>
<span class="sd">                    RKVersion.adjustmentUuid, RKVersion.type, RKMaster.UTI,</span>
<span class="sd">                    RKVersion.burstUuid, RKVersion.burstPickType,</span>
<span class="sd">                    RKVersion.specialType, RKMaster.modelID,</span>
<span class="sd">                    RKVersion.selfPortrait,</span>
<span class="sd">                    RKVersion.momentUuid,</span>
<span class="sd">                    RKVersion.rawMasterUuid,</span>
<span class="sd">                    RKVersion.nonRawMasterUuid,</span>
<span class="sd">                    RKMaster.alternateMasterUuid,</span>
<span class="sd">                    RKVersion.isInTrash,</span>
<span class="sd">                    RKVersion.processedHeight,</span>
<span class="sd">                    RKVersion.processedWidth,</span>
<span class="sd">                    RKVersion.orientation,</span>
<span class="sd">                    RKMaster.height,</span>
<span class="sd">                    RKMaster.width,</span>
<span class="sd">                    RKMaster.orientation,</span>
<span class="sd">                    RKMaster.originalFileSize,</span>
<span class="sd">                    RKVersion.subType,</span>
<span class="sd">                    RKVersion.inTrashDate,</span>
<span class="sd">                    RKVersion.showInLibrary,</span>
<span class="sd">                    RKMaster.fileIsReference,</span>
<span class="sd">                    RKMaster.importGroupUuid,</span>
<span class="sd">                    RKMaster.fingerprint,</span>
<span class="sd">                    RKVersion.imageTimeZoneName</span>
<span class="sd">                    FROM RKVersion, RKMaster</span>
<span class="sd">                    WHERE RKVersion.masterUuid = RKMaster.uuid&quot;&quot;&quot;</span>
            <span class="p">)</span>

        <span class="c1"># order of results</span>
        <span class="c1"># 0     RKVersion.uuid</span>
        <span class="c1"># 1     RKVersion.modelId</span>
        <span class="c1"># 2     RKVersion.masterUuid</span>
        <span class="c1"># 3     RKVersion.filename</span>
        <span class="c1"># 4     RKVersion.lastmodifieddate</span>
        <span class="c1"># 5     RKVersion.imageDate</span>
        <span class="c1"># 6     RKVersion.mainRating</span>
        <span class="c1"># 7     RKVersion.hasAdjustments</span>
        <span class="c1"># 8     RKVersion.hasKeywords</span>
        <span class="c1"># 9     RKVersion.imageTimeZoneOffsetSeconds</span>
        <span class="c1"># 10    RKMaster.volumeId</span>
        <span class="c1"># 11    RKMaster.imagePath</span>
        <span class="c1"># 12    RKVersion.extendedDescription</span>
        <span class="c1"># 13    RKVersion.name</span>
        <span class="c1"># 14    RKMaster.isMissing</span>
        <span class="c1"># 15    RKMaster.originalFileName</span>
        <span class="c1"># 16    RKVersion.isFavorite</span>
        <span class="c1"># 17    RKVersion.isHidden</span>
        <span class="c1"># 18    RKVersion.latitude</span>
        <span class="c1"># 19    RKVersion.longitude</span>
        <span class="c1"># 20    RKVersion.adjustmentUuid</span>
        <span class="c1"># 21    RKVersion.type</span>
        <span class="c1"># 22    RKMaster.UTI</span>
        <span class="c1"># 23    RKVersion.burstUuid</span>
        <span class="c1"># 24    RKVersion.burstPickType</span>
        <span class="c1"># 25    RKVersion.specialType</span>
        <span class="c1"># 26    RKMaster.modelID</span>
        <span class="c1"># 27    RKVersion.selfPortrait -- 1 if selfie, Photos &gt;= 3, not present for Photos &lt; 3</span>
        <span class="c1"># 28    RKVersion.momentID (# 27 for Photos &lt; 3)</span>
        <span class="c1"># 29    RKVersion.rawMasterUuid, -- UUID of RAW master</span>
        <span class="c1"># 30    RKVersion.nonRawMasterUuid, -- UUID of non-RAW master</span>
        <span class="c1"># 31    RKMaster.alternateMasterUuid -- UUID of alternate master (will be RAW master for JPEG and JPEG master for RAW)</span>
        <span class="c1"># 32    RKVersion.isInTrash</span>
        <span class="c1"># 33    RKVersion.processedHeight,</span>
        <span class="c1"># 34    RKVersion.processedWidth,</span>
        <span class="c1"># 35    RKVersion.orientation,</span>
        <span class="c1"># 36    RKMaster.height,</span>
        <span class="c1"># 37    RKMaster.width,</span>
        <span class="c1"># 38    RKMaster.orientation,</span>
        <span class="c1"># 39    RKMaster.originalFileSize</span>
        <span class="c1"># 40    RKVersion.subType</span>
        <span class="c1"># 41    RKVersion.inTrashDate</span>
        <span class="c1"># 42    RKVersion.showInLibrary -- is item visible in library (e.g. non-selected burst images are not visible)</span>
        <span class="c1"># 43    RKMaster.fileIsReference -- file is reference (imported without copying to Photos library)</span>
        <span class="c1"># 44    RKMaster.importGroupUuid -- to get date added from RKImportGroup</span>
        <span class="c1"># 45    RKMaster.fingerprint -- fingerprint / hash of the file</span>
        <span class="c1"># 46    RKVersion.imageTimeZoneName -- time zone name of the image</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">uuid</span>  <span class="c1"># stored here for easier debugging</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;modelID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;masterUuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;filename&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">])</span>

            <span class="c1"># There are sometimes negative values for lastmodifieddate in the database</span>
            <span class="c1"># I don&#39;t know what these mean but they will raise exception in datetime if</span>
            <span class="c1"># not accounted for</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;lastmodifieddate_timestamp&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;lastmodifieddate&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">photos_datetime_local</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">4</span><span class="p">])</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;imageTimeZoneOffsetSeconds&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">9</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;imageTimeZoneName&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">46</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;imageDate_timestamp&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;imageDate&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">photos_datetime</span><span class="p">(</span>
                <span class="n">row</span><span class="p">[</span><span class="mi">5</span><span class="p">],</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;imageTimeZoneOffsetSeconds&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="mi">0</span><span class="p">,</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;imageTimeZoneName&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="kc">None</span><span class="p">,</span>
                <span class="n">default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
            <span class="p">)</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;mainRating&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasAdjustments&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasKeywords&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">8</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;volumeId&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">10</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;imagePath&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">11</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;extendedDescription&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">12</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">13</span><span class="p">])</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;isMissing&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">14</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;originalFilename&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">15</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;favorite&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">16</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hidden&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">17</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;latitude&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">18</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;longitude&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">19</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;adjustmentUuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">20</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;adjustmentFormatID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="c1"># find type and UTI</span>
            <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">21</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
                <span class="c1"># photo</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">_PHOTO_TYPE</span>
            <span class="k">elif</span> <span class="n">row</span><span class="p">[</span><span class="mi">21</span><span class="p">]</span> <span class="o">==</span> <span class="mi">8</span><span class="p">:</span>
                <span class="c1"># movie</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">_MOVIE_TYPE</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># unknown</span>
                <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;WARNING: </span><span class="si">{</span><span class="n">uuid</span><span class="si">}</span><span class="s2"> found unknown type </span><span class="si">{</span><span class="n">row</span><span class="p">[</span><span class="mi">21</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">22</span><span class="p">]</span>

            <span class="c1"># The UTI in RKMaster will always be UTI of the original</span>
            <span class="c1"># Unlike Photos 5 which changes the UTI to match latest edit</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI_original&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">22</span><span class="p">]</span>

            <span class="c1"># UTI edited will be read from RKModelResource</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI_edited&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="c1"># handle burst photos</span>
            <span class="c1"># if burst photo, determine whether or not it&#39;s a selected burst photo</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;burstUUID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">23</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;burstPickType&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">24</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">23</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
                <span class="c1"># it&#39;s a burst photo</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;burst&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
                <span class="n">burst_uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">23</span><span class="p">]</span>
                <span class="k">if</span> <span class="n">burst_uuid</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_burst</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_burst</span><span class="p">[</span><span class="n">burst_uuid</span><span class="p">]</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_burst</span><span class="p">[</span><span class="n">burst_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">uuid</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># not a burst photo</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;burst&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>

            <span class="c1"># RKVersion.specialType</span>
            <span class="c1"># 1 == panorama</span>
            <span class="c1"># 2 == slow-mo movie</span>
            <span class="c1"># 3 == time-lapse movie</span>
            <span class="c1"># 4 == HDR</span>
            <span class="c1"># 5 == live photo</span>
            <span class="c1"># 6 == screenshot</span>
            <span class="c1"># 7 == JPEG/RAW pair</span>
            <span class="c1"># 8 == HDR live photo</span>
            <span class="c1"># 9 == portrait</span>

            <span class="c1"># get info on special types</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;specialType&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;masterModelID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">26</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;pk&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span>
                <span class="mi">26</span>
            <span class="p">]</span>  <span class="c1"># same as masterModelID, to match Photos 5</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;panorama&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;slow_mo&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;time_lapse&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">3</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hdr&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                <span class="kc">True</span> <span class="k">if</span> <span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">4</span> <span class="ow">or</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">8</span><span class="p">)</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;live_photo&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                <span class="kc">True</span> <span class="k">if</span> <span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">5</span> <span class="ow">or</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">8</span><span class="p">)</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;screenshot&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">6</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="c1"># screen-recording (not available &lt;= _PHOTOS_4_VERSION)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;screen_recording&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;portrait&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">9</span> <span class="k">else</span> <span class="kc">False</span>

            <span class="c1"># selfies (front facing camera, RKVersion.selfPortrait == 1)</span>
            <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">27</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;selfie&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">27</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;selfie&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;momentID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">28</span><span class="p">]</span>

            <span class="c1"># Init cloud details that will be filled in later if cloud asset</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;cloudAssetGUID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 5+</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;cloudLocalState&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 5+</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;cloudLibraryState&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;cloudStatus&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;cloudAvailable&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;incloud&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;cloudMasterGUID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 5+</span>

            <span class="c1"># associated RAW image info</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;has_raw&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">7</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI_raw&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;raw_data_length&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;raw_info&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;resource_type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 5</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;datastore_subtype&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 5</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;raw_master_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">29</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;non_raw_master_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">30</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;alt_master_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">31</span><span class="p">]</span>

            <span class="c1"># original resource choice (e.g. RAW or jpeg)</span>
            <span class="c1"># In Photos 5+, original_resource_choice set from:</span>
            <span class="c1"># ZADDITIONALASSETATTRIBUTES.ZORIGINALRESOURCECHOICE</span>
            <span class="c1"># = 0 if jpeg is selected as &quot;original&quot; in Photos (the default)</span>
            <span class="c1"># = 1 if RAW is selected as &quot;original&quot; in Photos</span>
            <span class="c1"># RKVersion.subType, RAW always appears to be 16</span>
            <span class="c1">#   4 = mov</span>
            <span class="c1">#   16 = RAW</span>
            <span class="c1">#   32 = JPEG</span>
            <span class="c1">#   64 = TIFF</span>
            <span class="c1">#   2048 = PNG</span>
            <span class="c1">#   32768 = HIEC</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;original_resource_choice&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                <span class="mi">1</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">40</span><span class="p">]</span> <span class="o">==</span> <span class="mi">16</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;has_raw&quot;</span><span class="p">]</span> <span class="k">else</span> <span class="mi">0</span>
            <span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;raw_is_original&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">bool</span><span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;original_resource_choice&quot;</span><span class="p">]</span>
            <span class="p">)</span>

            <span class="c1"># recently deleted items</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;intrash&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">32</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;trasheddate_timestamp&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">41</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;trasheddate&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">photos_datetime_local</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">41</span><span class="p">])</span>

            <span class="c1"># height/width/orientation</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;height&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">33</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;width&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">34</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;orientation&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">35</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;original_height&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">36</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;original_width&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">37</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;original_orientation&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">38</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;original_filesize&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">39</span><span class="p">]</span>

            <span class="c1"># visibility state</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;visibility_state&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">42</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;visible&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">42</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span>

            <span class="c1"># file is reference (not copied into Photos library)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;isreference&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">43</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;saved_asset_type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 5+</span>

            <span class="c1"># import session not yet handled for Photos 4</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;import_session&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;import_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">44</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;fok_import_session&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="c1"># fingerprint</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;masterFingerprint&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">45</span><span class="p">]</span>

            <span class="c1"># photos 5+ only, for shared photos</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;cloudownerhashedpersonid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="c1"># photos 7+ only, shared moments</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;moment_share&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="c1"># compute signatures for finding possible duplicates</span>
            <span class="n">signature</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_duplicate_signature</span><span class="p">(</span><span class="n">uuid</span><span class="p">)</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_signatures</span><span class="p">[</span><span class="n">signature</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">uuid</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_signatures</span><span class="p">[</span><span class="n">signature</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">uuid</span><span class="p">]</span>

        <span class="c1"># get additional details from RKMaster, needed for RAW processing</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing additional photo details.&quot;</span><span class="p">)</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT</span>
<span class="sd">                RKMaster.uuid,</span>
<span class="sd">                RKMaster.volumeId,</span>
<span class="sd">                RKMaster.imagePath,</span>
<span class="sd">                RKMaster.isMissing,</span>
<span class="sd">                RKMaster.originalFileName,</span>
<span class="sd">                RKMaster.UTI,</span>
<span class="sd">                RKMaster.modelID,</span>
<span class="sd">                RKMaster.fileSize,</span>
<span class="sd">                RKMaster.isTrulyRaw,</span>
<span class="sd">                RKMaster.alternateMasterUuid,</span>
<span class="sd">                RKMaster.filename</span>
<span class="sd">                FROM RKMaster</span>
<span class="sd">            &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># Order of results:</span>
        <span class="c1"># 0     RKMaster.uuid,</span>
        <span class="c1"># 1     RKMaster.volumeId,</span>
        <span class="c1"># 2     RKMaster.imagePath,</span>
        <span class="c1"># 3     RKMaster.isMissing,</span>
        <span class="c1"># 4     RKMaster.originalFileName,</span>
        <span class="c1"># 5     RKMaster.UTI,</span>
        <span class="c1"># 6     RKMaster.modelID,</span>
        <span class="c1"># 7     RKMaster.fileSize,</span>
        <span class="c1"># 8     RKMaster.isTrulyRaw,</span>
        <span class="c1"># 9     RKMaster.alternateMasterUuid</span>
        <span class="c1"># 10    RKMaster.filename</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">info</span> <span class="o">=</span> <span class="p">{}</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">uuid</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;volumeId&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;imagePath&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;isMissing&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;originalFilename&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">4</span><span class="p">])</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;UTI&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;modelID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;fileSize&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;isTrulyRAW&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">8</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;alternateMasterUuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">9</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;filename&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">10</span><span class="p">])</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_master</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span> <span class="o">=</span> <span class="n">info</span>

        <span class="c1"># get details needed to find path of the edited photos</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT RKVersion.uuid, RKVersion.adjustmentUuid, RKModelResource.modelId,</span>
<span class="sd">                RKModelResource.resourceTag, RKModelResource.UTI, RKVersion.specialType,</span>
<span class="sd">                RKModelResource.attachedModelType, RKModelResource.resourceType</span>
<span class="sd">                FROM RKVersion</span>
<span class="sd">                JOIN RKModelResource on RKModelResource.attachedModelId = RKVersion.modelId</span>
<span class="sd">                ORDER BY RKModelResource.modelId</span>
<span class="sd">            &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># Order of results:</span>
        <span class="c1"># 0     RKVersion.uuid</span>
        <span class="c1"># 1     RKVersion.adjustmentUuid</span>
        <span class="c1"># 2     RKModelResource.modelId</span>
        <span class="c1"># 3     RKModelResource.resourceTag</span>
        <span class="c1"># 4     RKModelResource.UTI</span>
        <span class="c1"># 5     RKVersion.specialType</span>
        <span class="c1"># 6     RKModelResource.attachedModelType (2 = edit)</span>
        <span class="c1"># 7     RKModelResource.resourceType (4 = photo, 8 = video)</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
                <span class="c1"># get info on adjustments (edits)</span>
                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;adjustmentUuid&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">]:</span>
                    <span class="k">if</span> <span class="p">(</span>
                        <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;UNADJUSTEDNONRAW&quot;</span>
                        <span class="ow">and</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;UNADJUSTED&quot;</span>
                        <span class="ow">and</span> <span class="n">row</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2</span>
                    <span class="p">):</span>
                        <span class="n">resource_type</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span>
                        <span class="c1"># UTI_edited will be set to the appropriate UTI for the edited resource below</span>
                        <span class="c1"># a live photo that&#39;s edited will have both a photo and video resource but the photo</span>
                        <span class="c1"># UTI will be used for the edited live photo, see #859</span>
                        <span class="k">if</span> <span class="n">resource_type</span> <span class="o">==</span> <span class="mi">4</span><span class="p">:</span>
                            <span class="c1"># photo</span>
                            <span class="k">if</span> <span class="s2">&quot;edit_resource_id_photo&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">]:</span>
                                <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
                                    <span class="sa">f</span><span class="s2">&quot;WARNING: found more than one edit_resource_id_photo for UUID </span><span class="si">{</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="s2">,adjustmentUUID </span><span class="si">{</span><span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2">, modelID </span><span class="si">{</span><span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span>
                                <span class="p">)</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;edit_resource_id_photo&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI_edited_photo&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span>
                        <span class="k">elif</span> <span class="n">resource_type</span> <span class="o">==</span> <span class="mi">8</span><span class="p">:</span>
                            <span class="c1"># video</span>
                            <span class="k">if</span> <span class="s2">&quot;edit_resource_id_video&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">]:</span>
                                <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
                                    <span class="sa">f</span><span class="s2">&quot;WARNING: found more than one edit_resource_id_video for UUID </span><span class="si">{</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="s2">,adjustmentUUID </span><span class="si">{</span><span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2">, modelID </span><span class="si">{</span><span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span>
                                <span class="p">)</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;edit_resource_id_video&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI_edited_video&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span>

        <span class="c1"># get details on external edits</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT RKVersion.uuid,</span>
<span class="sd">                RKVersion.adjustmentUuid,</span>
<span class="sd">                RKAdjustmentData.originator,</span>
<span class="sd">                RKAdjustmentData.format</span>
<span class="sd">                FROM RKVersion, RKAdjustmentData</span>
<span class="sd">                WHERE RKVersion.adjustmentUuid = RKAdjustmentData.uuid &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;adjustmentFormatID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>

        <span class="c1"># get details to find path of live photos</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT</span>
<span class="sd">                RKVersion.uuid,</span>
<span class="sd">                RKModelResource.modelId,</span>
<span class="sd">                RKModelResource.UTI,</span>
<span class="sd">                RKVersion.specialType,</span>
<span class="sd">                RKModelResource.attachedModelType,</span>
<span class="sd">                RKModelResource.resourceType,</span>
<span class="sd">                RKModelResource.isOnDisk</span>
<span class="sd">                FROM RKVersion</span>
<span class="sd">                INNER JOIN RKMaster on RKVersion.masterUuid = RKMaster.uuid</span>
<span class="sd">                INNER JOIN RKModelResource on RKMaster.modelId = RKModelResource.attachedModelId</span>
<span class="sd">                WHERE RKModelResource.UTI = &#39;com.apple.quicktime-movie&#39;</span>
<span class="sd">              &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># Order of results</span>
        <span class="c1"># 0     RKVersion.uuid,</span>
        <span class="c1"># 1     RKModelResource.modelId,</span>
        <span class="c1"># 2     RKModelResource.UTI,</span>
        <span class="c1"># 3     RKVersion.specialType,</span>
        <span class="c1"># 4     RKModelResource.attachedModelType,</span>
        <span class="c1"># 5     RKModelResource.resourceType</span>
        <span class="c1"># 6     RKModelResource.isOnDisk</span>

        <span class="c1"># TODO: don&#39;t think we need most of these fields, remove from SQL query?</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;live_model_id&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;modeResourceIsOnDisk&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                    <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="kc">False</span>
                <span class="p">)</span>

        <span class="c1"># init any uuids that had no edits or live photos</span>
        <span class="c1"># also initialized UTI_edited and edit_resource_id</span>
        <span class="k">for</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
            <span class="k">if</span> <span class="s2">&quot;edit_resource_id_photo&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">]:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;edit_resource_id_photo&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="k">if</span> <span class="s2">&quot;edit_resource_id_video&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">]:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;edit_resource_id_video&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="k">if</span> <span class="s2">&quot;UTI_edited_photo&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">]:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI_edited_photo&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="k">if</span> <span class="s2">&quot;UTI_edited_video&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">]:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI_edited_video&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="c1"># UTI_edited will be set to the appropriate UTI for the edited resource below</span>
            <span class="c1"># a live photo that&#39;s edited will have both a photo and video resource but the photo</span>
            <span class="c1"># UTI will be used for the edited live photo</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI_edited&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI_edited_photo&quot;</span><span class="p">]</span>
                <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI_edited_video&quot;</span><span class="p">]</span>
            <span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;edit_resource_id&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;edit_resource_id_photo&quot;</span><span class="p">]</span>
                <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;edit_resource_id_video&quot;</span><span class="p">]</span>
            <span class="p">)</span>
            <span class="k">if</span> <span class="s2">&quot;live_model_id&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">]:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;live_model_id&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;modeResourceIsOnDisk&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="c1"># get cloud details</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT</span>
<span class="sd">                RKVersion.uuid,</span>
<span class="sd">                RKMaster.cloudLibraryState,</span>
<span class="sd">                RKCloudResource.available,</span>
<span class="sd">                RKCloudResource.status</span>
<span class="sd">                FROM RKCloudResource</span>
<span class="sd">                INNER JOIN RKMaster ON RKMaster.fingerprint = RKCloudResource.fingerprint</span>
<span class="sd">                INNER JOIN RKVersion ON RKVersion.masterUuid = RKMaster.uuid &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># Order of results</span>
        <span class="c1"># 0  RKVersion.uuid,</span>
        <span class="c1"># 1  RKMaster.cloudLibraryState,</span>
        <span class="c1"># 2  RKCloudResource.available,</span>
        <span class="c1"># 3  RKCloudResource.status</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;cloudLibraryState&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;cloudAvailable&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;cloudStatus&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;incloud&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="kc">False</span>

        <span class="c1"># get location data</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing location data.&quot;</span><span class="p">)</span>
        <span class="c1"># get the country codes</span>
        <span class="n">country_codes</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT modelID, countryCode FROM RKPlace WHERE countryCode IS NOT NULL &quot;</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="n">countries</span> <span class="o">=</span> <span class="p">{</span><span class="n">code</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span> <span class="n">code</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">code</span> <span class="ow">in</span> <span class="n">country_codes</span><span class="p">}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_countries</span> <span class="o">=</span> <span class="n">countries</span>

        <span class="c1"># get the place data</span>
        <span class="n">place_data</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT modelID, defaultName, type, area FROM RKPlace&quot;</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="n">places</span> <span class="o">=</span> <span class="p">{</span><span class="n">p</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span> <span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">place_data</span><span class="p">}</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_places</span> <span class="o">=</span> <span class="n">places</span>

        <span class="c1"># get import data</span>
        <span class="n">import_data</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT modelID, uuid, name, importDate from RKImportGroup&quot;</span>
        <span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_import_group</span> <span class="o">=</span> <span class="p">{</span><span class="n">i</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span> <span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">import_data</span><span class="p">}</span>

        <span class="k">for</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
            <span class="c1"># get placeId which is then used to lookup defaultName</span>
            <span class="n">place_ids_query</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
                <span class="sa">f</span><span class="s2">&quot;SELECT placeId FROM RKPlaceForVersion WHERE versionId = &#39;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s1">&#39;modelID&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&#39;&quot;</span>
            <span class="p">)</span>

            <span class="n">place_ids</span> <span class="o">=</span> <span class="p">[</span><span class="nb">id</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="nb">id</span> <span class="ow">in</span> <span class="n">place_ids_query</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;placeIDs&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">place_ids</span>
            <span class="n">country_code</span> <span class="o">=</span> <span class="p">[</span><span class="n">countries</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">place_ids</span> <span class="k">if</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">countries</span><span class="p">]</span>
            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">country_code</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
                <span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Found more than one country code for uuid: </span><span class="si">{</span><span class="n">uuid</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

            <span class="k">if</span> <span class="n">country_code</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;countryCode&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">country_code</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;countryCode&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="c1"># get the place info that matches the RKPlace modelIDs for this photo</span>
            <span class="c1"># (place_ids), sort by area (element 3 of the place_data tuple in places)</span>
            <span class="c1"># area could be None so assume 0 if it is (issue #230)</span>
            <span class="n">place_names</span> <span class="o">=</span> <span class="p">[</span>
                <span class="n">pname</span>
                <span class="k">for</span> <span class="n">pname</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span>
                    <span class="p">[</span><span class="n">places</span><span class="p">[</span><span class="n">p</span><span class="p">]</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">places</span> <span class="k">if</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">place_ids</span><span class="p">],</span>
                    <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">place</span><span class="p">:</span> <span class="n">place</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="k">if</span> <span class="n">place</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="mi">0</span><span class="p">,</span>
                <span class="p">)</span>
            <span class="p">]</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;placeNames&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">place_names</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;reverse_geolocation&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 5</span>

            <span class="c1"># add date added</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">import_session</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_import_group</span><span class="p">[</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;import_uuid&quot;</span><span class="p">]</span>
                <span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;added_date&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">photos_datetime_local</span><span class="p">(</span>
                    <span class="n">import_session</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">default</span><span class="o">=</span><span class="kc">True</span>
                <span class="p">)</span>
            <span class="k">except</span> <span class="p">(</span><span class="ne">KeyError</span><span class="p">,</span> <span class="ne">IndexError</span><span class="p">):</span>
                <span class="c1"># use the default datetime</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;added_date&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">photos_datetime_local</span><span class="p">(</span>
                    <span class="kc">None</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">True</span>
                <span class="p">)</span>

        <span class="c1"># build album_titles dictionary</span>
        <span class="k">for</span> <span class="n">album_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">:</span>
            <span class="n">title</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">[</span><span class="n">album_id</span><span class="p">][</span><span class="s2">&quot;title&quot;</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">title</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_titles</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_titles</span><span class="p">[</span><span class="n">title</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">album_id</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_titles</span><span class="p">[</span><span class="n">title</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">album_id</span><span class="p">]</span>

        <span class="c1"># add volume name to _dbphotos_master</span>
        <span class="k">for</span> <span class="n">info</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_master</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="c1"># issue 230: have seen bad volumeID values</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;volume&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbvolumes</span><span class="p">[</span><span class="n">info</span><span class="p">[</span><span class="s2">&quot;volumeId&quot;</span><span class="p">]]</span>
                    <span class="k">if</span> <span class="n">info</span><span class="p">[</span><span class="s2">&quot;volumeId&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
                    <span class="k">else</span> <span class="kc">None</span>
                <span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;volume&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="c1"># add data on RAW images</span>
        <span class="k">for</span> <span class="n">info</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="k">if</span> <span class="n">info</span><span class="p">[</span><span class="s2">&quot;has_raw&quot;</span><span class="p">]:</span>
                <span class="n">raw_uuid</span> <span class="o">=</span> <span class="n">info</span><span class="p">[</span><span class="s2">&quot;raw_master_uuid&quot;</span><span class="p">]</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;raw_info&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_master</span><span class="p">[</span><span class="n">raw_uuid</span><span class="p">]</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;UTI_raw&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_master</span><span class="p">[</span><span class="n">raw_uuid</span><span class="p">][</span><span class="s2">&quot;UTI&quot;</span><span class="p">]</span>
                <span class="n">non_raw_uuid</span> <span class="o">=</span> <span class="n">info</span><span class="p">[</span><span class="s2">&quot;non_raw_master_uuid&quot;</span><span class="p">]</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;raw_pair_info&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_master</span><span class="p">[</span><span class="n">non_raw_uuid</span><span class="p">]</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;raw_info&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;UTI_raw&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;raw_pair_info&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="c1"># placeholders for shared library info on Photos 8+</span>
        <span class="k">for</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;active_library_participation_state&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;library_scope_share_state&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;library_scope&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="c1"># done with the database connection</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

        <span class="c1"># process faces</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing face details.&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_process_faceinfo</span><span class="p">()</span>

        <span class="c1"># add faces and keywords to photo data</span>
        <span class="k">for</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
            <span class="c1"># keywords</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasKeywords&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;keywords&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;keywords&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasPersons&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;persons&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasPersons&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;persons&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;albums&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasAlbums&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;albums&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasAlbums&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>

            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;volumeId&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
                <span class="c1"># issue 230: have seen bad volumeID values</span>
                <span class="k">try</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;volume&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbvolumes</span><span class="p">[</span>
                        <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;volumeId&quot;</span><span class="p">]</span>
                    <span class="p">]</span>
                <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;volume&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;volume&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="c1"># done processing, dump debug data if requested</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Done processing details from Photos library.&quot;</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_build_album_folder_hierarchy_4</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">folders</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Recursively build folder/album hierarchy</span>
<span class="sd">        uuid: parent uuid of the album being processed</span>
<span class="sd">             (parent uuid is a folder in RKFolders)</span>
<span class="sd">        folders: dict holding the folder hierarchy</span>
<span class="sd">        NOTE: This implementation is different than _build_album_folder_hierarchy_5</span>
<span class="sd">        which takes the uuid of the album being processed.  Here uuid is the parent uuid</span>
<span class="sd">        of the parent folder album because in Photos &lt;=4, folders are in RKFolders and</span>
<span class="sd">        albums in RKAlbums.  In Photos 5, folders are just special albums</span>
<span class="sd">        with kind = _PHOTOS_5_FOLDER_KIND&quot;&quot;&quot;</span>

        <span class="n">parent_uuid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfolder_details</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;parentFolderUuid&quot;</span><span class="p">]</span>

        <span class="k">if</span> <span class="n">parent_uuid</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">folders</span>

        <span class="k">if</span> <span class="n">parent_uuid</span> <span class="ow">in</span> <span class="n">_PHOTOS_4_TOP_LEVEL_ALBUMS</span><span class="p">:</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">folders</span><span class="p">:</span>
                <span class="c1"># this is a top-level folder with no sub-folders</span>
                <span class="n">folders</span> <span class="o">=</span> <span class="p">{</span><span class="n">uuid</span><span class="p">:</span> <span class="kc">None</span><span class="p">}</span>
            <span class="c1"># at top of hierarchy, we&#39;re done</span>
            <span class="k">return</span> <span class="n">folders</span>

        <span class="c1"># recurse to keep building</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">folders</span><span class="p">:</span>
            <span class="c1"># first time building</span>
            <span class="n">folders</span> <span class="o">=</span> <span class="p">{</span><span class="n">uuid</span><span class="p">:</span> <span class="kc">None</span><span class="p">}</span>
        <span class="n">folders</span> <span class="o">=</span> <span class="p">{</span><span class="n">parent_uuid</span><span class="p">:</span> <span class="n">folders</span><span class="p">}</span>
        <span class="n">folders</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_build_album_folder_hierarchy_4</span><span class="p">(</span><span class="n">parent_uuid</span><span class="p">,</span> <span class="n">folders</span><span class="o">=</span><span class="n">folders</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">folders</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_process_database5</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;process the Photos database to extract info</span>
<span class="sd">        works on Photos version 5 and version 6</span>

<span class="sd">        This is a big hairy 700 line function that should probably be refactored</span>
<span class="sd">        but it works so don&#39;t touch it.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;_process_database5&quot;</span><span class="p">)</span>
        <span class="n">verbose</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_verbose</span>
        <span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span> <span class="o">=</span> <span class="n">sqlite_open_ro</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_tmp_db</span><span class="p">)</span>

        <span class="c1"># some of the tables/columns have different names in different versions of Photos</span>
        <span class="c1"># set local var for readability</span>
        <span class="n">photos_ver</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span>
        <span class="n">verbose</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;Photos database version: </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_num</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span><span class="p">)</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_num</span><span class="p">(</span><span class="n">photos_ver</span><span class="p">)</span><span class="si">}</span><span class="s2">.&quot;</span>
        <span class="p">)</span>
        <span class="n">asset_table</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;ASSET&quot;</span><span class="p">]</span>
        <span class="n">keyword_join</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;KEYWORD_JOIN&quot;</span><span class="p">]</span>
        <span class="n">asset_album_table</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;ASSET_ALBUM_TABLE&quot;</span><span class="p">]</span>
        <span class="n">album_join</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;ALBUM_JOIN&quot;</span><span class="p">]</span>
        <span class="n">album_sort</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;ALBUM_SORT_ORDER&quot;</span><span class="p">]</span>
        <span class="n">asset_album_join</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;ASSET_ALBUM_JOIN&quot;</span><span class="p">]</span>
        <span class="n">import_fok</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;IMPORT_FOK&quot;</span><span class="p">]</span>
        <span class="n">depth_state</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;DEPTH_STATE&quot;</span><span class="p">]</span>
        <span class="n">uti_original_column</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;UTI_ORIGINAL&quot;</span><span class="p">]</span>
        <span class="n">hdr_type_column</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;HDR_TYPE&quot;</span><span class="p">]</span>
        <span class="n">master_fingerprint</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;MASTER_FINGERPRINT&quot;</span><span class="p">]</span>
        <span class="n">has_adjustments</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;HAS_ADJUSTMENTS&quot;</span><span class="p">]</span>

        <span class="c1"># Look for all combinations of persons and pictures</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Getting information about persons&quot;</span><span class="p">)</span>

        <span class="c1"># get info to associate persons with photos</span>
        <span class="c1"># then get detected faces in each photo and link to persons</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing persons in photos.&quot;</span><span class="p">)</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot; SELECT</span>
<span class="sd">                ZPERSON.Z_PK,</span>
<span class="sd">                ZPERSON.ZPERSONUUID,</span>
<span class="sd">                ZPERSON.ZFULLNAME,</span>
<span class="sd">                ZPERSON.ZFACECOUNT,</span>
<span class="sd">                ZPERSON.ZKEYFACE,</span>
<span class="sd">                ZPERSON.ZDISPLAYNAME,</span>
<span class="sd">                ZPERSON.ZTYPE,</span>
<span class="sd">                ZPERSON.ZMANUALORDER</span>
<span class="sd">                FROM ZPERSON</span>
<span class="sd">            &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># 0     ZPERSON.Z_PK,</span>
        <span class="c1"># 1     ZPERSON.ZPERSONUUID,</span>
        <span class="c1"># 2     ZPERSON.ZFULLNAME,</span>
        <span class="c1"># 3     ZPERSON.ZFACECOUNT,</span>
        <span class="c1"># 4     ZPERSON.ZKEYFACE,</span>
        <span class="c1"># 5     ZPERSON.ZDISPLAYNAME</span>
        <span class="c1"># 6     ZPERSON.ZTYPE,  # ZTYPE = 1 == favorite, 0 == not favorite</span>
        <span class="c1"># 7     ZPERSON.ZMANUALORDER # favorites are sorted by ZMANUALORDER</span>

        <span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">pk</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">fullname</span> <span class="o">=</span> <span class="p">(</span>
                <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span> <span class="ow">and</span> <span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">)</span>
                <span class="k">else</span> <span class="n">_UNKNOWN_PERSON</span>
            <span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
                <span class="s2">&quot;pk&quot;</span><span class="p">:</span> <span class="n">pk</span><span class="p">,</span>
                <span class="s2">&quot;uuid&quot;</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
                <span class="s2">&quot;fullname&quot;</span><span class="p">:</span> <span class="n">fullname</span><span class="p">,</span>
                <span class="s2">&quot;facecount&quot;</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span>
                <span class="s2">&quot;keyface&quot;</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span>
                <span class="s2">&quot;displayname&quot;</span><span class="p">:</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">person</span><span class="p">[</span><span class="mi">5</span><span class="p">]),</span>
                <span class="s2">&quot;photo_uuid&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
                <span class="s2">&quot;keyface_uuid&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
                <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">6</span><span class="p">],</span>
                <span class="s2">&quot;manualorder&quot;</span><span class="p">:</span> <span class="n">person</span><span class="p">[</span><span class="mi">7</span><span class="p">],</span>
            <span class="p">}</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_fullname</span><span class="p">[</span><span class="n">fullname</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">pk</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_fullname</span><span class="p">[</span><span class="n">fullname</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">pk</span><span class="p">]</span>

        <span class="c1"># get info on keyface -- some photos have null keyface so can&#39;t do a single query</span>
        <span class="c1"># (at least not with my SQL skills)</span>
        <span class="n">asset_fk</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;DETECTED_FACE_ASSET_FK&quot;</span><span class="p">]</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;&quot;&quot; SELECT</span>
<span class="s2">                ZPERSON.Z_PK,</span>
<span class="s2">                ZPERSON.ZKEYFACE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">                ZDETECTEDFACE.ZUUID</span>
<span class="s2">                FROM ZPERSON, ZDETECTEDFACE, </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                WHERE ZDETECTEDFACE.Z_PK = ZPERSON.ZKEYFACE AND</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_fk</span><span class="si">}</span><span class="s2"> = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">            &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># 0 ZPERSON.Z_PK,</span>
        <span class="c1"># 1 ZPERSON.ZKEYFACE,</span>
        <span class="c1"># 2 ZGENERICASSET.ZUUID,</span>
        <span class="c1"># 3 ZDETECTEDFACE.ZUUID</span>

        <span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">pk</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">][</span><span class="s2">&quot;photo_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">][</span><span class="s2">&quot;keyface_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unexpected KeyError _dbpersons_pk[</span><span class="si">{</span><span class="n">pk</span><span class="si">}</span><span class="s2">]&quot;</span><span class="p">)</span>

        <span class="c1"># get information on detected faces</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing detected faces in photos.&quot;</span><span class="p">)</span>
        <span class="n">person_fk</span> <span class="o">=</span> <span class="n">_DB_TABLE_NAMES</span><span class="p">[</span><span class="n">photos_ver</span><span class="p">][</span><span class="s2">&quot;DETECTED_FACE_PERSON_FK&quot;</span><span class="p">]</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;&quot;&quot; SELECT</span>
<span class="s2">                ZPERSON.Z_PK,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID</span>
<span class="s2">                FROM ZPERSON, ZDETECTEDFACE, </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                WHERE </span><span class="si">{</span><span class="n">person_fk</span><span class="si">}</span><span class="s2"> = ZPERSON.Z_PK AND</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_fk</span><span class="si">}</span><span class="s2"> = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">            &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># 0     ZPERSON.Z_PK,</span>
        <span class="c1"># 1     ZGENERICASSET.ZUUID,</span>

        <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">pk</span> <span class="o">=</span> <span class="n">face</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">face</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">pk</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">pk</span><span class="p">]</span>

            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">uuid</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">uuid</span><span class="p">]</span>

        <span class="c1"># get details about albums</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing albums.&quot;</span><span class="p">)</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;&quot;&quot; SELECT</span>
<span class="s2">                ZGENERICALBUM.ZUUID,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">album_sort</span><span class="si">}</span>
<span class="s2">                FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                JOIN </span><span class="si">{</span><span class="n">asset_album_table</span><span class="si">}</span><span class="s2"> ON </span><span class="si">{</span><span class="n">album_join</span><span class="si">}</span><span class="s2"> = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">                JOIN ZGENERICALBUM ON ZGENERICALBUM.Z_PK = </span><span class="si">{</span><span class="n">asset_album_join</span><span class="si">}</span>
<span class="s2">            &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># 0     ZGENERICALBUM.ZUUID,</span>
        <span class="c1"># 1     ZGENERICASSET.ZUUID,</span>
        <span class="c1"># 2     Z_26ASSETS.Z_FOK_34ASSETS</span>

        <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="c1"># store by uuid in _dbalbums_uuid and by album in _dbalbums_album</span>
            <span class="n">album_uuid</span> <span class="o">=</span> <span class="n">album</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">photo_uuid</span> <span class="o">=</span> <span class="n">album</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
            <span class="n">sort_order</span> <span class="o">=</span> <span class="n">album</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span><span class="p">[</span><span class="n">photo_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">album_uuid</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span><span class="p">[</span><span class="n">photo_uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span>

            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">photo_uuid</span><span class="p">,</span> <span class="n">sort_order</span><span class="p">))</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">[(</span><span class="n">photo_uuid</span><span class="p">,</span> <span class="n">sort_order</span><span class="p">)]</span>

        <span class="c1"># now get additional details about albums</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="s2">&quot;SELECT &quot;</span>
            <span class="s2">&quot;ZUUID, &quot;</span>  <span class="c1"># 0</span>
            <span class="s2">&quot;ZTITLE, &quot;</span>  <span class="c1"># 1</span>
            <span class="s2">&quot;ZCLOUDLOCALSTATE, &quot;</span>  <span class="c1"># 2</span>
            <span class="s2">&quot;ZCLOUDOWNERFIRSTNAME, &quot;</span>  <span class="c1"># 3</span>
            <span class="s2">&quot;ZCLOUDOWNERLASTNAME, &quot;</span>  <span class="c1"># 4</span>
            <span class="s2">&quot;ZCLOUDOWNERHASHEDPERSONID, &quot;</span>  <span class="c1"># 5</span>
            <span class="s2">&quot;ZKIND, &quot;</span>  <span class="c1"># 6</span>
            <span class="s2">&quot;ZPARENTFOLDER, &quot;</span>  <span class="c1"># 7</span>
            <span class="s2">&quot;Z_PK, &quot;</span>  <span class="c1"># 8</span>
            <span class="s2">&quot;ZTRASHEDSTATE, &quot;</span>  <span class="c1"># 9</span>
            <span class="s2">&quot;ZCREATIONDATE, &quot;</span>  <span class="c1"># 10</span>
            <span class="s2">&quot;ZSTARTDATE, &quot;</span>  <span class="c1"># 11</span>
            <span class="s2">&quot;ZENDDATE, &quot;</span>  <span class="c1"># 12</span>
            <span class="s2">&quot;ZCUSTOMSORTASCENDING, &quot;</span>  <span class="c1"># 13</span>
            <span class="s2">&quot;ZCUSTOMSORTKEY &quot;</span>  <span class="c1"># 14</span>
            <span class="s2">&quot;FROM ZGENERICALBUM &quot;</span>
        <span class="p">)</span>
        <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">[</span><span class="n">album</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{</span>
                <span class="s2">&quot;_uuid&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
                <span class="s2">&quot;title&quot;</span><span class="p">:</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">album</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span>
                <span class="s2">&quot;cloudlocalstate&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span>
                <span class="s2">&quot;cloudownerfirstname&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span>
                <span class="s2">&quot;cloudownderlastname&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span>
                <span class="s2">&quot;cloudownerhashedpersonid&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">5</span><span class="p">],</span>
                <span class="s2">&quot;cloudlibrarystate&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>  <span class="c1"># Photos 4</span>
                <span class="s2">&quot;cloudidentifier&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>  <span class="c1"># Photos 4</span>
                <span class="s2">&quot;kind&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">6</span><span class="p">],</span>
                <span class="s2">&quot;parentfolder&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">7</span><span class="p">],</span>
                <span class="s2">&quot;pk&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">8</span><span class="p">],</span>
                <span class="s2">&quot;intrash&quot;</span><span class="p">:</span> <span class="kc">False</span> <span class="k">if</span> <span class="n">album</span><span class="p">[</span><span class="mi">9</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="kc">True</span><span class="p">,</span>
                <span class="s2">&quot;creation_date&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">10</span><span class="p">]</span>
                <span class="ow">or</span> <span class="mi">0</span><span class="p">,</span>  <span class="c1"># iPhone Photos.sqlite can have null value</span>
                <span class="s2">&quot;start_date&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">11</span><span class="p">]</span> <span class="ow">or</span> <span class="mi">0</span><span class="p">,</span>
                <span class="s2">&quot;end_date&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">12</span><span class="p">]</span> <span class="ow">or</span> <span class="mi">0</span><span class="p">,</span>
                <span class="s2">&quot;customsortascending&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">13</span><span class="p">],</span>
                <span class="s2">&quot;customsortkey&quot;</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">14</span><span class="p">],</span>
            <span class="p">}</span>

            <span class="c1"># add cross-reference by pk to uuid</span>
            <span class="c1"># needed to extract folder hierarchy</span>
            <span class="c1"># in Photos &gt;= 5, folders are special albums</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_pk</span><span class="p">[</span><span class="n">album</span><span class="p">[</span><span class="mi">8</span><span class="p">]]</span> <span class="o">=</span> <span class="n">album</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

        <span class="c1"># get pk of root folder</span>
        <span class="n">root_uuid</span> <span class="o">=</span> <span class="p">[</span>
            <span class="n">album</span>
            <span class="k">for</span> <span class="n">album</span><span class="p">,</span> <span class="n">details</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
            <span class="k">if</span> <span class="n">details</span><span class="p">[</span><span class="s2">&quot;kind&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">_PHOTOS_5_ROOT_FOLDER_KIND</span>
        <span class="p">]</span>
        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">root_uuid</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error finding root folder: </span><span class="si">{</span><span class="n">root_uuid</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_folder_root_pk</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">[</span><span class="n">root_uuid</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="s2">&quot;pk&quot;</span><span class="p">]</span>

        <span class="c1"># build _dbalbum_folders which is in form uuid: [list of parent uuids]</span>
        <span class="c1"># TODO: look at this code...it works but I think I album can only be in a single folder</span>
        <span class="c1"># which means there&#39;s a code path that will never get executed</span>
        <span class="k">for</span> <span class="n">album</span><span class="p">,</span> <span class="n">details</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="n">pk_parent</span> <span class="o">=</span> <span class="n">details</span><span class="p">[</span><span class="s2">&quot;parentfolder&quot;</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">pk_parent</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
                <span class="k">continue</span>

            <span class="k">try</span><span class="p">:</span>
                <span class="n">parent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_pk</span><span class="p">[</span><span class="n">pk_parent</span><span class="p">]</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Did not find uuid for album </span><span class="si">{</span><span class="n">album</span><span class="si">}</span><span class="s2"> pk </span><span class="si">{</span><span class="n">pk_parent</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_parent_folders</span><span class="p">[</span><span class="n">album</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">parent</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_parent_folders</span><span class="p">[</span><span class="n">album</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">parent</span><span class="p">]</span>

        <span class="k">for</span> <span class="n">album</span><span class="p">,</span> <span class="n">details</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="c1"># if details[&quot;kind&quot;] in [_PHOTOS_5_ALBUM_KIND, _PHOTOS_5_FOLDER_KIND]:</span>
            <span class="k">if</span> <span class="n">details</span><span class="p">[</span><span class="s2">&quot;kind&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">_PHOTOS_5_ALBUM_KIND</span><span class="p">:</span>
                <span class="n">folder_hierarchy</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_build_album_folder_hierarchy_5</span><span class="p">(</span><span class="n">album</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album</span><span class="p">]</span> <span class="o">=</span> <span class="n">folder_hierarchy</span>
            <span class="k">elif</span> <span class="n">details</span><span class="p">[</span><span class="s2">&quot;kind&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">_PHOTOS_5_SHARED_ALBUM_KIND</span><span class="p">:</span>
                <span class="c1"># shared albums can&#39;t be in folders</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="c1"># get details on keywords</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing keywords.&quot;</span><span class="p">)</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;&quot;&quot;SELECT ZKEYWORD.ZTITLE, </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID</span>
<span class="s2">                FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">                JOIN Z_1KEYWORDS ON Z_1KEYWORDS.Z_1ASSETATTRIBUTES = ZADDITIONALASSETATTRIBUTES.Z_PK</span>
<span class="s2">                JOIN ZKEYWORD ON ZKEYWORD.Z_PK = </span><span class="si">{</span><span class="n">keyword_join</span><span class="si">}</span><span class="s2"> &quot;&quot;&quot;</span>
        <span class="p">)</span>
        <span class="k">for</span> <span class="n">keyword_title</span><span class="p">,</span> <span class="n">keyword_uuid</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">keyword_title</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">keyword_title</span><span class="p">)</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">keyword_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword_title</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">keyword_uuid</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword_uuid</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword_title</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">keyword_uuid</span><span class="p">]</span>

        <span class="c1"># get details on disk volumes</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">&quot;SELECT ZUUID, ZNAME from ZFILESYSTEMVOLUME&quot;</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">vol</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbvolumes</span><span class="p">[</span><span class="n">vol</span><span class="p">[</span><span class="mi">0</span><span class="p">]]</span> <span class="o">=</span> <span class="n">vol</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>

        <span class="c1"># get details about photos</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing photo details.&quot;</span><span class="p">)</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;&quot;&quot;SELECT </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">master_fingerprint</span><span class="si">}</span><span class="s2">,</span>
<span class="s2">                ZADDITIONALASSETATTRIBUTES.ZTITLE,</span>
<span class="s2">                ZADDITIONALASSETATTRIBUTES.ZORIGINALFILENAME,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZMODIFICATIONDATE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZDATECREATED,</span>
<span class="s2">                ZADDITIONALASSETATTRIBUTES.ZTIMEZONEOFFSET,</span>
<span class="s2">                ZADDITIONALASSETATTRIBUTES.ZINFERREDTIMEZONEOFFSET,</span>
<span class="s2">                ZADDITIONALASSETATTRIBUTES.ZTIMEZONENAME,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZHIDDEN,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZFAVORITE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZDIRECTORY,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZFILENAME,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZLATITUDE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZLONGITUDE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">has_adjustments</span><span class="si">}</span><span class="s2">,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZCLOUDBATCHPUBLISHDATE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZKIND,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUNIFORMTYPEIDENTIFIER,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZAVALANCHEUUID,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZAVALANCHEPICKTYPE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZKINDSUBTYPE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">hdr_type_column</span><span class="si">}</span><span class="s2">,</span>
<span class="s2">                ZADDITIONALASSETATTRIBUTES.ZCAMERACAPTUREDEVICE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZCLOUDASSETGUID,</span>
<span class="s2">                ZADDITIONALASSETATTRIBUTES.ZREVERSELOCATIONDATA,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZMOMENT,</span>
<span class="s2">                ZADDITIONALASSETATTRIBUTES.ZORIGINALRESOURCECHOICE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZTRASHEDSTATE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZHEIGHT,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZWIDTH,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZORIENTATION,</span>
<span class="s2">                ZADDITIONALASSETATTRIBUTES.ZORIGINALHEIGHT,</span>
<span class="s2">                ZADDITIONALASSETATTRIBUTES.ZORIGINALWIDTH,</span>
<span class="s2">                ZADDITIONALASSETATTRIBUTES.ZORIGINALORIENTATION,</span>
<span class="s2">                ZADDITIONALASSETATTRIBUTES.ZORIGINALFILESIZE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">depth_state</span><span class="si">}</span><span class="s2">,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZADJUSTMENTTIMESTAMP,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZVISIBILITYSTATE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZTRASHEDDATE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZSAVEDASSETTYPE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZADDEDDATE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZCLOUDOWNERHASHEDPERSONID,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZMOMENTSHARE</span>
<span class="s2">                FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">                ORDER BY </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID  &quot;&quot;&quot;</span>
        <span class="p">)</span>
        <span class="c1"># Order of results</span>
        <span class="c1"># 0    SELECT ZGENERICASSET.ZUUID,</span>
        <span class="c1"># 1    ZADDITIONALASSETATTRIBUTES.ZMASTERFINGERPRINT,</span>
        <span class="c1"># 2    ZADDITIONALASSETATTRIBUTES.ZTITLE,</span>
        <span class="c1"># 3    ZADDITIONALASSETATTRIBUTES.ZORIGINALFILENAME,</span>
        <span class="c1"># 4    ZGENERICASSET.ZMODIFICATIONDATE,</span>
        <span class="c1"># 5    ZGENERICASSET.ZDATECREATED,</span>
        <span class="c1"># 6    ZADDITIONALASSETATTRIBUTES.ZTIMEZONEOFFSET,</span>
        <span class="c1"># 7    ZADDITIONALASSETATTRIBUTES.ZINFERREDTIMEZONEOFFSET,</span>
        <span class="c1"># 8    ZADDITIONALASSETATTRIBUTES.ZTIMEZONENAME,</span>
        <span class="c1"># 9    ZGENERICASSET.ZHIDDEN,</span>
        <span class="c1"># 10   ZGENERICASSET.ZFAVORITE,</span>
        <span class="c1"># 11   ZGENERICASSET.ZDIRECTORY,</span>
        <span class="c1"># 12   ZGENERICASSET.ZFILENAME,</span>
        <span class="c1"># 13   ZGENERICASSET.ZLATITUDE,</span>
        <span class="c1"># 14   ZGENERICASSET.ZLONGITUDE,</span>
        <span class="c1"># 15   ZGENERICASSET.ZHASADJUSTMENTS</span>
        <span class="c1"># 16   ZCLOUDBATCHPUBLISHDATE   -- If not null, indicates a shared photo</span>
        <span class="c1"># 17   ZKIND, -- 0 = photo, 1 = movie</span>
        <span class="c1"># 18   ZUNIFORMTYPEIDENTIFIER  -- UTI</span>
        <span class="c1"># 19   ZGENERICASSET.ZAVALANCHEUUID, -- if not NULL, is burst photo</span>
        <span class="c1"># 20   ZGENERICASSET.ZAVALANCHEPICKTYPE -- if not 2, is a selected burst photo</span>
        <span class="c1"># 21   ZGENERICASSET.ZKINDSUBTYPE -- determine if live photos, etc</span>
        <span class="c1"># 22   ZGENERICASSET.ZCUSTOMRENDEREDVALUE -- determine if HDR photo</span>
        <span class="c1"># 23   ZADDITIONALASSETATTRIBUTES.ZCAMERACAPTUREDEVICE -- 1 if selfie (front facing camera)</span>
        <span class="c1"># 24   ZGENERICASSET.ZCLOUDASSETGUID  -- not null if asset is cloud asset</span>
        <span class="c1">#       (e.g. user has &quot;iCloud Photos&quot; checked in Photos preferences)</span>
        <span class="c1"># 25   ZADDITIONALASSETATTRIBUTES.ZREVERSELOCATIONDATA -- reverse geolocation data</span>
        <span class="c1"># 26   ZGENERICASSET.ZMOMENT -- FK for ZMOMENT.Z_PK</span>
        <span class="c1"># 27   ZADDITIONALASSETATTRIBUTES.ZORIGINALRESOURCECHOICE -- 1 if associated RAW image is original else 0</span>
        <span class="c1"># 28   ZGENERICASSET.ZTRASHEDSTATE -- 0 if not in trash, 1 if in trash</span>
        <span class="c1"># 29   ZGENERICASSET.ZHEIGHT,</span>
        <span class="c1"># 30   ZGENERICASSET.ZWIDTH,</span>
        <span class="c1"># 31   ZGENERICASSET.ZORIENTATION,</span>
        <span class="c1"># 32   ZADDITIONALASSETATTRIBUTES.ZORIGINALHEIGHT,</span>
        <span class="c1"># 33   ZADDITIONALASSETATTRIBUTES.ZORIGINALWIDTH,</span>
        <span class="c1"># 34   ZADDITIONALASSETATTRIBUTES.ZORIGINALORIENTATION,</span>
        <span class="c1"># 35   ZADDITIONALASSETATTRIBUTES.ZORIGINALFILESIZE</span>
        <span class="c1"># 36   ZGENERICASSET.ZDEPTHSTATES / ZASSET.ZDEPTHTYPE</span>
        <span class="c1"># 37   ZGENERICASSET.ZADJUSTMENTTIMESTAMP -- when was photo edited?</span>
        <span class="c1"># 38   ZGENERICASSET.ZVISIBILITYSTATE -- 0 if visible, 2 if not (e.g. a burst image)</span>
        <span class="c1"># 39   ZGENERICASSET.ZTRASHEDDATE -- date item placed in the trash or null if not in trash</span>
        <span class="c1"># 40   ZGENERICASSET.ZSAVEDASSETTYPE -- how item imported</span>
        <span class="c1"># 41   ZGENERICASSET.ZADDEDDATE -- date item added to the library</span>
        <span class="c1"># 42   ZGENERICASSET.Z_PK -- primary key</span>
        <span class="c1"># 43   ZGENERICASSET.ZCLOUDOWNERHASHEDPERSONID -- used to look up owner name (for shared photos)</span>
        <span class="c1"># 44   ZASSET.ZMOMENTSHARE -- FK for ZSHARE (shared moments, Photos 5+; in Photos 7+ these are in the scopes/momentshared folder)</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">info</span> <span class="o">=</span> <span class="p">{}</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">uuid</span>  <span class="c1"># stored here for easier debugging</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;modelID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;masterUuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;masterFingerprint&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>

            <span class="c1"># There are sometimes negative values for lastmodifieddate in the database</span>
            <span class="c1"># I don&#39;t know what these mean but they will raise exception in datetime if</span>
            <span class="c1"># not accounted for</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;lastmodifieddate_timestamp&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">37</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;lastmodifieddate&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">photos_datetime_local</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">37</span><span class="p">])</span>

            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;imageTimeZoneOffsetSeconds&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;imageTimeZoneName&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">8</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;imageDate_timestamp&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;imageDate&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">photos_datetime</span><span class="p">(</span>
                <span class="n">timestamp</span><span class="o">=</span><span class="n">row</span><span class="p">[</span><span class="mi">5</span><span class="p">],</span>
                <span class="n">tzoffset</span><span class="o">=</span><span class="n">info</span><span class="p">[</span><span class="s2">&quot;imageTimeZoneOffsetSeconds&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="mi">0</span><span class="p">,</span>
                <span class="n">tzname</span><span class="o">=</span><span class="n">info</span><span class="p">[</span><span class="s2">&quot;imageTimeZoneName&quot;</span><span class="p">],</span>
                <span class="n">default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
            <span class="p">)</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;hidden&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">9</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;favorite&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">10</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;originalFilename&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">])</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;filename&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">12</span><span class="p">])</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">12</span><span class="p">]</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>  <span class="c1"># 1445</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;directory&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">11</span><span class="p">]</span> <span class="ow">or</span> <span class="s2">&quot;&quot;</span>  <span class="c1"># 1445</span>

            <span class="c1"># set latitude and longitude</span>
            <span class="c1"># if both latitude and longitude = -180.0, then they are NULL</span>
            <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">13</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mf">180.0</span> <span class="ow">and</span> <span class="n">row</span><span class="p">[</span><span class="mi">14</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mf">180.0</span><span class="p">:</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;latitude&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;longitude&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;latitude&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">13</span><span class="p">]</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;longitude&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">14</span><span class="p">]</span>

            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;hasAdjustments&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">15</span><span class="p">]</span>

            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;cloudbatchpublishdate&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">16</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;shared&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">16</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="kc">False</span>

            <span class="c1"># these will get filled in later</span>
            <span class="c1"># init to avoid key errors</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;extendedDescription&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># fill this in later</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;localAvailability&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;remoteAvailability&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;isMissing&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;adjustmentUuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;adjustmentFormatID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="c1"># find type</span>
            <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">17</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">_PHOTO_TYPE</span>
            <span class="k">elif</span> <span class="n">row</span><span class="p">[</span><span class="mi">17</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">_MOVIE_TYPE</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;WARNING: </span><span class="si">{</span><span class="n">uuid</span><span class="si">}</span><span class="s2"> found unknown type </span><span class="si">{</span><span class="n">row</span><span class="p">[</span><span class="mi">17</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;UTI&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">18</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;UTI_original&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># filled in later</span>

            <span class="c1"># handle burst photos</span>
            <span class="c1"># if burst photo, determine whether or not it&#39;s a selected burst photo</span>
            <span class="c1"># in Photos 5, burstUUID is called avalancheUUID</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;burstUUID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">19</span><span class="p">]</span>  <span class="c1"># avalancheUUID</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;burstPickType&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">20</span><span class="p">]</span>  <span class="c1"># avalanchePickType</span>
            <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">19</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
                <span class="c1"># it&#39;s a burst photo</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;burst&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
                <span class="n">burst_uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">19</span><span class="p">]</span>
                <span class="k">if</span> <span class="n">burst_uuid</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_burst</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_burst</span><span class="p">[</span><span class="n">burst_uuid</span><span class="p">]</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos_burst</span><span class="p">[</span><span class="n">burst_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">uuid</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># not a burst photo</span>
                <span class="n">info</span><span class="p">[</span><span class="s2">&quot;burst&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>

            <span class="c1"># Info on sub-type (live photo, panorama, etc)</span>
            <span class="c1"># ZGENERICASSET.ZKINDSUBTYPE</span>
            <span class="c1"># 1 == panorama</span>
            <span class="c1"># 2 == live photo</span>
            <span class="c1"># 10 = screenshot</span>
            <span class="c1"># 100 = shared movie (MP4) ??</span>
            <span class="c1"># 101 = slow-motion video</span>
            <span class="c1"># 102 = Time lapse video</span>
            <span class="c1"># 103 = Screen Recordings</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;subtype&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">21</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;live_photo&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">21</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;screenshot&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">21</span><span class="p">]</span> <span class="o">==</span> <span class="mi">10</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;screen_recording&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">21</span><span class="p">]</span> <span class="o">==</span> <span class="mi">103</span> <span class="k">else</span> <span class="kc">False</span>

            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;slow_mo&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">21</span><span class="p">]</span> <span class="o">==</span> <span class="mi">101</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;time_lapse&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">21</span><span class="p">]</span> <span class="o">==</span> <span class="mi">102</span> <span class="k">else</span> <span class="kc">False</span>

            <span class="c1"># Handle HDR photos and portraits</span>
            <span class="c1"># ZGENERICASSET.ZCUSTOMRENDEREDVALUE</span>
            <span class="c1"># 3 = HDR photo</span>
            <span class="c1"># 4 = non-HDR version of the photo</span>
            <span class="c1"># 6 = panorama</span>
            <span class="c1"># &gt; 6 = portrait (sometimes, see ZDEPTHSTATE/ZDEPTHTYPE)</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;customRenderedValue&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">22</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;hdr&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">22</span><span class="p">]</span> <span class="o">==</span> <span class="mi">3</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;depth_state&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">36</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;portrait&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">36</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span> <span class="k">else</span> <span class="kc">False</span>

            <span class="c1"># Set panorama from either KindSubType or RenderedValue</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;panorama&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">21</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span> <span class="ow">or</span> <span class="n">row</span><span class="p">[</span><span class="mi">22</span><span class="p">]</span> <span class="o">==</span> <span class="mi">6</span> <span class="k">else</span> <span class="kc">False</span>

            <span class="c1"># Handle selfies (front facing camera, ZCAMERACAPTUREDEVICE=1)</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;selfie&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">23</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="kc">False</span>

            <span class="c1"># Determine if photo is part of cloud library (ZGENERICASSET.ZCLOUDASSETGUID not NULL)</span>
            <span class="c1"># Initialize cloud fields that will filled in later</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;cloudAssetGUID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">24</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;cloudLocalState&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;incloud&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;cloudLibraryState&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 4</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;cloudStatus&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 4</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;cloudAvailable&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 4</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;cloudMasterGUID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="c1"># reverse geolocation info</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;reverse_geolocation&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;placeIDs&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 4</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;placeNames&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 4</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;countryCode&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 4</span>

            <span class="c1"># moment info</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;momentID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">26</span><span class="p">]</span>

            <span class="c1"># original resource choice (e.g. RAW or jpeg)</span>
            <span class="c1"># for images part of a RAW/jpeg pair,</span>
            <span class="c1"># ZADDITIONALASSETATTRIBUTES.ZORIGINALRESOURCECHOICE</span>
            <span class="c1"># = 0 if jpeg is selected as &quot;original&quot; in Photos (the default)</span>
            <span class="c1"># = 1 if RAW is selected as &quot;original&quot; in Photos</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;original_resource_choice&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">27</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;raw_is_original&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">27</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="kc">False</span>

            <span class="c1"># recently deleted items</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;intrash&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">28</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="kc">False</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;trasheddate_timestamp&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">39</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;trasheddate&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">photos_datetime_local</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">39</span><span class="p">])</span>

            <span class="c1"># height/width/orientation</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;height&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">29</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;width&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">30</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;orientation&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">31</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;original_height&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">32</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;original_width&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">33</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;original_orientation&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">34</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;original_filesize&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">35</span><span class="p">]</span>

            <span class="c1"># visibility state, visible (True) if 0, otherwise not visible (False)</span>
            <span class="c1"># only values I&#39;ve seen are 0 for visible, 2 for not-visible</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;visibility_state&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">38</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;visible&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">38</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span>

            <span class="c1"># ZSAVEDASSETTYPE Values:</span>
            <span class="c1"># 3: imported by copying to Photos library</span>
            <span class="c1"># 4: shared iCloud photo</span>
            <span class="c1"># 6: imported by iCloud (e.g. from iPhone)</span>
            <span class="c1"># 10: referenced file (not copied to Photos library)</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;saved_asset_type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">40</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;isreference&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">40</span><span class="p">]</span> <span class="o">==</span> <span class="mi">10</span>

            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;added_date&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">photos_datetime_local</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">41</span><span class="p">],</span> <span class="n">default</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>

            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;pk&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">42</span><span class="p">]</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;cloudownerhashedpersonid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">43</span><span class="p">]</span>

            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;moment_share&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">44</span><span class="p">]</span>

            <span class="c1"># initialize import session info which will be filled in later</span>
            <span class="c1"># not every photo has an import session so initialize all records now</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;import_session&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;fok_import_session&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;import_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="c1"># associated RAW image info</span>
            <span class="c1"># will be filled in later</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;has_raw&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;raw_data_length&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;UTI_raw&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;datastore_subtype&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;resource_type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;raw_master_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 4</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;non_raw_master_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 4</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;alt_master_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 4</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;raw_info&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>  <span class="c1"># Photos 4</span>

            <span class="c1"># Photos 4 only</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;edit_resource_id_photo&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;edit_resource_id_video&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;UTI_edited_photo&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;UTI_edited_video&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="c1"># placeholder for shared library info (Photos 8+)</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;active_library_participation_state&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;library_scope_share_state&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">info</span><span class="p">[</span><span class="s2">&quot;library_scope&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span> <span class="o">=</span> <span class="n">info</span>

            <span class="c1"># compute signatures for finding possible duplicates</span>
            <span class="n">signature</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_duplicate_signature</span><span class="p">(</span><span class="n">uuid</span><span class="p">)</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_signatures</span><span class="p">[</span><span class="n">signature</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">uuid</span><span class="p">)</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_signatures</span><span class="p">[</span><span class="n">signature</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">uuid</span><span class="p">]</span>

            <span class="c1"># # if row[19] is not None and ((row[20] == 2) or (row[20] == 4)):</span>
            <span class="c1"># # burst photo</span>
            <span class="c1"># if row[19] is not None:</span>
            <span class="c1">#     # burst photo, add to _dbphotos_burst</span>
            <span class="c1">#     info[&quot;burst&quot;] = True</span>
            <span class="c1">#     burst_uuid = row[19]</span>
            <span class="c1">#     if burst_uuid not in self._dbphotos_burst:</span>
            <span class="c1">#         self._dbphotos_burst[burst_uuid] = {}</span>
            <span class="c1">#     self._dbphotos_burst[burst_uuid][uuid] = info</span>
            <span class="c1"># else:</span>
            <span class="c1">#     info[&quot;burst&quot;] = False</span>

        <span class="c1"># get info on import sessions</span>
        <span class="c1"># 0    ZGENERICASSET.ZUUID</span>
        <span class="c1"># 1    ZGENERICASSET.ZIMPORTSESSION</span>
        <span class="c1"># 2    ZGENERICASSET.Z_FOK_IMPORTSESSION</span>
        <span class="c1"># 3    ZGENERICALBUM.ZUUID,</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing import sessions.&quot;</span><span class="p">)</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;&quot;&quot;SELECT</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZIMPORTSESSION,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">import_fok</span><span class="si">}</span><span class="s2">,</span>
<span class="s2">                ZGENERICALBUM.ZUUID</span>
<span class="s2">                FROM</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                JOIN ZGENERICALBUM ON ZGENERICALBUM.Z_PK = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZIMPORTSESSION</span>
<span class="s2">            &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;import_session&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;fok_import_session&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;import_uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No info record for uuid </span><span class="si">{</span><span class="n">uuid</span><span class="si">}</span><span class="s2"> for import session&quot;</span><span class="p">)</span>

        <span class="c1"># Get extended description</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing additional photo details.&quot;</span><span class="p">)</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;&quot;&quot;SELECT </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">                ZASSETDESCRIPTION.ZLONGDESCRIPTION</span>
<span class="s2">                FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">                JOIN ZASSETDESCRIPTION ON ZASSETDESCRIPTION.Z_PK = ZADDITIONALASSETATTRIBUTES.ZASSETDESCRIPTION</span>
<span class="s2">                ORDER BY </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID &quot;&quot;&quot;</span>
        <span class="p">)</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;extendedDescription&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
                    <span class="sa">f</span><span class="s2">&quot;WARNING: found description </span><span class="si">{</span><span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2"> but no photo for </span><span class="si">{</span><span class="n">uuid</span><span class="si">}</span><span class="s2">&quot;</span>
                <span class="p">)</span>

        <span class="c1"># get information about adjusted/edited photos</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;&quot;&quot;SELECT </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">has_adjustments</span><span class="si">}</span><span class="s2">,</span>
<span class="s2">                ZUNMANAGEDADJUSTMENT.ZADJUSTMENTFORMATIDENTIFIER</span>
<span class="s2">                FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">, ZUNMANAGEDADJUSTMENT</span>
<span class="s2">                JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">                WHERE ZADDITIONALASSETATTRIBUTES.ZUNMANAGEDADJUSTMENT = ZUNMANAGEDADJUSTMENT.Z_PK &quot;&quot;&quot;</span>
        <span class="p">)</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;adjustmentFormatID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
                    <span class="sa">f</span><span class="s2">&quot;WARNING: found adjustmentformatidentifier </span><span class="si">{</span><span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="si">}</span><span class="s2"> but no photo for uuid </span><span class="si">{</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span>
                <span class="p">)</span>

        <span class="c1"># Find missing photos</span>
        <span class="c1"># TODO: this code is very kludgy and I had to make lots of assumptions</span>
        <span class="c1"># it&#39;s probably wrong and needs to be re-worked once I figure out how to reliably</span>
        <span class="c1"># determine if a photo is missing in Photos 5</span>

        <span class="c1"># Get info on remote/local availability for photos in shared albums</span>
        <span class="c1"># Also get UTI of original image (zdatastoresubtype = 1)</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">&gt;=</span> <span class="mi">7</span><span class="p">:</span>
            <span class="n">sql_missing</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;&quot;&quot; SELECT</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">                ZINTERNALRESOURCE.ZLOCALAVAILABILITY,</span>
<span class="s2">                ZINTERNALRESOURCE.ZREMOTEAVAILABILITY,</span>
<span class="s2">                ZINTERNALRESOURCE.ZDATASTORESUBTYPE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">uti_original_column</span><span class="si">}</span><span class="s2">,</span>
<span class="s2">                null</span>
<span class="s2">                FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">                JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET</span>
<span class="s2">                WHERE  ZDATASTORESUBTYPE = 1 OR ZDATASTORESUBTYPE = 3 &quot;&quot;&quot;</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">sql_missing</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;&quot;&quot; SELECT</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">                ZINTERNALRESOURCE.ZLOCALAVAILABILITY,</span>
<span class="s2">                ZINTERNALRESOURCE.ZREMOTEAVAILABILITY,</span>
<span class="s2">                ZINTERNALRESOURCE.ZDATASTORESUBTYPE,</span>
<span class="s2">                </span><span class="si">{</span><span class="n">uti_original_column</span><span class="si">}</span><span class="s2">,</span>
<span class="s2">                ZUNIFORMTYPEIDENTIFIER.ZIDENTIFIER</span>
<span class="s2">                FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">                JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET</span>
<span class="s2">                JOIN ZUNIFORMTYPEIDENTIFIER ON ZUNIFORMTYPEIDENTIFIER.Z_PK = ZINTERNALRESOURCE.ZUNIFORMTYPEIDENTIFIER</span>
<span class="s2">                WHERE  ZDATASTORESUBTYPE = 1 OR ZDATASTORESUBTYPE = 3 &quot;&quot;&quot;</span>

        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">sql_missing</span><span class="p">)</span>

        <span class="c1"># Order of results:</span>
        <span class="c1"># 0 {asset_table}.ZUUID,</span>
        <span class="c1"># 1 ZINTERNALRESOURCE.ZLOCALAVAILABILITY,</span>
        <span class="c1"># 2 ZINTERNALRESOURCE.ZREMOTEAVAILABILITY,</span>
        <span class="c1"># 3 ZINTERNALRESOURCE.ZDATASTORESUBTYPE,</span>
        <span class="c1"># 4 ZINTERNALRESOURCE.ZUNIFORMTYPEIDENTIFIER,</span>
        <span class="c1"># 5 ZUNIFORMTYPEIDENTIFIER.ZIDENTIFIER</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;localAvailability&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;remoteAvailability&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI_original&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span>

                <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;isMissing&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;isMissing&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>

        <span class="c1"># get information on local/remote availability</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;&quot;&quot; SELECT </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">                ZINTERNALRESOURCE.ZLOCALAVAILABILITY,</span>
<span class="s2">                ZINTERNALRESOURCE.ZREMOTEAVAILABILITY</span>
<span class="s2">                FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">                JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZFINGERPRINT = </span><span class="si">{</span><span class="n">master_fingerprint</span><span class="si">}</span><span class="s2"> &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;localAvailability&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;remoteAvailability&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>

                <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;isMissing&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;isMissing&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>

        <span class="c1"># get information about cloud sync state</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;&quot;&quot; SELECT</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">                ZCLOUDMASTER.ZCLOUDLOCALSTATE,</span>
<span class="s2">                ZCLOUDMASTER.ZCLOUDMASTERGUID</span>
<span class="s2">                FROM ZCLOUDMASTER, </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                WHERE </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZMASTER = ZCLOUDMASTER.Z_PK &quot;&quot;&quot;</span>
        <span class="p">)</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;cloudLocalState&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;incloud&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mi">3</span> <span class="k">else</span> <span class="kc">False</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;cloudMasterGUID&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>

        <span class="c1"># get information about associted RAW images</span>
        <span class="c1"># RAW images have ZDATASTORESUBTYPE = 17</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">&gt;=</span> <span class="mi">7</span><span class="p">:</span>
            <span class="n">sql_raw</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;&quot;&quot; SELECT</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">                ZINTERNALRESOURCE.ZDATALENGTH,</span>
<span class="s2">                null,</span>
<span class="s2">                ZINTERNALRESOURCE.ZDATASTORESUBTYPE,</span>
<span class="s2">                ZINTERNALRESOURCE.ZRESOURCETYPE,</span>
<span class="s2">                ZINTERNALRESOURCE.ZFILESYSTEMBOOKMARK</span>
<span class="s2">                FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET</span>
<span class="s2">                JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">                WHERE ZINTERNALRESOURCE.ZDATASTORESUBTYPE = 17</span>
<span class="s2">            &quot;&quot;&quot;</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">sql_raw</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;&quot;&quot; SELECT</span>
<span class="s2">                </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">                ZINTERNALRESOURCE.ZDATALENGTH,</span>
<span class="s2">                ZUNIFORMTYPEIDENTIFIER.ZIDENTIFIER,</span>
<span class="s2">                ZINTERNALRESOURCE.ZDATASTORESUBTYPE,</span>
<span class="s2">                ZINTERNALRESOURCE.ZRESOURCETYPE,</span>
<span class="s2">                ZINTERNALRESOURCE.ZFILESYSTEMBOOKMARK</span>
<span class="s2">                FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">                JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET</span>
<span class="s2">                JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">                JOIN ZUNIFORMTYPEIDENTIFIER ON ZUNIFORMTYPEIDENTIFIER.Z_PK =  ZINTERNALRESOURCE.ZUNIFORMTYPEIDENTIFIER</span>
<span class="s2">                WHERE ZINTERNALRESOURCE.ZDATASTORESUBTYPE = 17</span>
<span class="s2">            &quot;&quot;&quot;</span>

        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">sql_raw</span><span class="p">)</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;has_raw&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;raw_data_length&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI_raw&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;datastore_subtype&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;resource_type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;raw_bookmark&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span>

        <span class="c1"># get paths for the relative imports for RAW+JPEG images</span>
        <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;&quot;&quot; SELECT</span>
<span class="s2">            </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID,</span>
<span class="s2">            ZFILESYSTEMVOLUME.ZNAME,</span>
<span class="s2">            ZFILESYSTEMBOOKMARK.ZPATHRELATIVETOVOLUME</span>
<span class="s2">            FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span>
<span class="s2">            JOIN ZINTERNALRESOURCE ON ZINTERNALRESOURCE.ZASSET = ZADDITIONALASSETATTRIBUTES.ZASSET</span>
<span class="s2">            JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
<span class="s2">            JOIN ZFILESYSTEMBOOKMARK ON ZFILESYSTEMBOOKMARK.ZRESOURCE = ZINTERNALRESOURCE.Z_PK</span>
<span class="s2">            JOIN ZFILESYSTEMVOLUME ON ZFILESYSTEMVOLUME.Z_PK = ZINTERNALRESOURCE.ZFILESYSTEMVOLUME</span>
<span class="s2">            WHERE ZINTERNALRESOURCE.ZDATASTORESUBTYPE = 17</span>
<span class="s2">            &quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># path to the raw image will be /Volumes/ZFILESYSTEMVOLUME.ZNAME/ZFILESYSTEMBOOKMARK.ZPATHRELATIVETOVOLUME</span>
        <span class="c1"># 0: {asset_table}.ZUUID, -- UUID</span>
        <span class="c1"># 1: ZFILESYSTEMVOLUME.ZNAME, -- name of the volume</span>
        <span class="c1"># 2: ZFILESYSTEMBOOKMARK.ZPATHRELATIVETOVOLUME -- path to the raw image</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;raw_volume&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;raw_relative_path&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>

        <span class="c1"># add faces and keywords to photo data</span>
        <span class="k">for</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
            <span class="c1"># keywords</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasKeywords&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;keywords&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_uuid</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasKeywords&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;keywords&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasPersons&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;persons&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_uuid</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasPersons&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;persons&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>

            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;albums&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_uuid</span><span class="p">[</span><span class="n">uuid</span><span class="p">]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasAlbums&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;albums&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasAlbums&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>

        <span class="c1"># build album_titles dictionary</span>
        <span class="k">for</span> <span class="n">album_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">:</span>
            <span class="n">title</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">[</span><span class="n">album_id</span><span class="p">][</span><span class="s2">&quot;title&quot;</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">title</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_titles</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_titles</span><span class="p">[</span><span class="n">title</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">album_id</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_titles</span><span class="p">[</span><span class="n">title</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">album_id</span><span class="p">]</span>

        <span class="c1"># country codes (only used in Photos &lt;=4)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_countries</span> <span class="o">=</span> <span class="kc">None</span>

        <span class="c1"># close connection and remove temporary files</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

        <span class="c1"># process face info</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing face details.&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_process_faceinfo</span><span class="p">()</span>

        <span class="c1"># process search info</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing photo labels.&quot;</span><span class="p">)</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_process_searchinfo</span><span class="p">()</span>
        <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="c1"># The search db is sometimes missing or missing the right tables;</span>
            <span class="c1"># osxphotos can operate without reading the search db so this is not fatal</span>
            <span class="c1"># but labels won&#39;t be available.</span>
            <span class="c1"># I&#39;ve not yet figured out why or how to fix it but w</span>
            <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
                <span class="sa">f</span><span class="s2">&quot;Error reading photo labels (labels &amp; search_info will not be available): </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span>
            <span class="p">)</span>

        <span class="c1"># process exif info</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing EXIF details.&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_process_exifinfo</span><span class="p">()</span>

        <span class="c1"># process computed scores</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing computed aesthetic scores.&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_process_scoreinfo</span><span class="p">()</span>

        <span class="c1"># process shared comments/likes</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing comments and likes for shared photos.&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_process_comments</span><span class="p">()</span>

        <span class="c1"># process moments</span>
        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing moments.&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_process_moments</span><span class="p">()</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">photos_version</span> <span class="o">&gt;=</span> <span class="mi">7</span><span class="p">:</span>
            <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing syndication info.&quot;</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_process_syndicationinfo</span><span class="p">()</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">photos_version</span> <span class="o">&gt;=</span> <span class="mi">8</span><span class="p">:</span>
            <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing shared iCloud library info&quot;</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_process_shared_library_info</span><span class="p">()</span>

        <span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Done processing details from Photos library.&quot;</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_process_moments</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Process data from ZMOMENT table&quot;&quot;&quot;</span>
        <span class="c1"># _db_moment_pk is dict in form {pk: {moment info}} by ZMOMENT.Z_PK</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">&lt;=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span>
                <span class="sa">f</span><span class="s2">&quot;Moment info implemented for this database version&quot;</span>
            <span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_process_moment_5</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_process_moment_5</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Process moment info for Photos 5 databases&quot;&quot;&quot;</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_db_moment_pk</span> <span class="o">=</span> <span class="p">{}</span>

        <span class="n">results</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
            <span class="sa">f</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            Z_PK,</span>
<span class="s2">            ZTIMEZONEOFFSET,</span>
<span class="s2">            ZTRASHEDSTATE,</span>
<span class="s2">            ZAPPROXIMATELATITUDE,</span>
<span class="s2">            ZAPPROXIMATELONGITUDE,</span>
<span class="s2">            ZENDDATE,</span>
<span class="s2">            ZMODIFICATIONDATE,</span>
<span class="s2">            ZREPRESENTATIVEDATE,</span>
<span class="s2">            ZSTARTDATE,</span>
<span class="s2">            ZSUBTITLE,</span>
<span class="s2">            ZTITLE,</span>
<span class="s2">            ZUUID</span>
<span class="s2">            FROM ZMOMENT&quot;&quot;&quot;</span>
        <span class="p">)</span>

        <span class="c1"># results</span>
        <span class="c1"># 0  Z_PK,</span>
        <span class="c1"># 1  ZTIMEZONEOFFSET,</span>
        <span class="c1"># 2  ZTRASHEDSTATE,</span>
        <span class="c1"># 3  ZAPPROXIMATELATITUDE,</span>
        <span class="c1"># 4  ZAPPROXIMATELONGITUDE,</span>
        <span class="c1"># 5  ZENDDATE,</span>
        <span class="c1"># 6  ZMODIFICATIONDATE,</span>
        <span class="c1"># 7  ZREPRESENTATIVEDATE,</span>
        <span class="c1"># 8  ZSTARTDATE,</span>
        <span class="c1"># 9  ZSUBTITLE,</span>
        <span class="c1"># 10 ZTITLE,</span>
        <span class="c1"># 11 ZUUID</span>

        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="n">moment_info</span> <span class="o">=</span> <span class="p">{}</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;pk&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;timezoneOffset&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;trashedState&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;approximateLatitude&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;approximateLongitude&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;endDate&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;modificationDate&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;representativeDate&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">7</span><span class="p">]</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;startDate&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">8</span><span class="p">]</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;subtitle&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">9</span><span class="p">])</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;title&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">10</span><span class="p">])</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;uuid&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">11</span><span class="p">]</span>

            <span class="c1"># if both lat/lon == -180, then it means location undefined</span>
            <span class="k">if</span> <span class="p">(</span>
                <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;approximateLatitude&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mf">180.0</span>
                <span class="ow">and</span> <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;approximateLongitude&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mf">180.0</span>
            <span class="p">):</span>
                <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;latitude&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
                <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;longitude&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;latitude&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;approximateLatitude&quot;</span><span class="p">]</span>
                <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;longitude&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;approximateLongitude&quot;</span><span class="p">]</span>

            <span class="c1"># process date stamps</span>
            <span class="n">offset_seconds</span> <span class="o">=</span> <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;timezoneOffset&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="mi">0</span>
            <span class="k">for</span> <span class="n">date_name</span> <span class="ow">in</span> <span class="p">[</span>
                <span class="s2">&quot;startDate&quot;</span><span class="p">,</span>
                <span class="s2">&quot;endDate&quot;</span><span class="p">,</span>
                <span class="s2">&quot;modificationDate&quot;</span><span class="p">,</span>
                <span class="s2">&quot;representativeDate&quot;</span><span class="p">,</span>
            <span class="p">]:</span>
                <span class="n">date_stamp</span> <span class="o">=</span> <span class="n">moment_info</span><span class="p">[</span><span class="n">date_name</span><span class="p">]</span>
                <span class="n">moment_info</span><span class="p">[</span><span class="n">date_name</span> <span class="o">+</span> <span class="s2">&quot;_timestamp&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">moment_info</span><span class="p">[</span><span class="n">date_name</span><span class="p">]</span>
                <span class="n">moment_date</span> <span class="o">=</span> <span class="n">photos_datetime</span><span class="p">(</span><span class="n">date_stamp</span><span class="p">,</span> <span class="n">offset_seconds</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
                <span class="n">moment_info</span><span class="p">[</span><span class="n">date_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">moment_date</span>

            <span class="c1"># process title/subtitle</span>
            <span class="c1"># use unicodedata.normalize with KFKC instead of normalize_unicode as is done elsewhere</span>
            <span class="c1"># to replace non-breaking whitespace chars with spaces as Photos uses \xa0 as space in Moment titles, subtitles</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;title&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                <span class="n">normalize</span><span class="p">(</span><span class="s2">&quot;NFKC&quot;</span><span class="p">,</span> <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;title&quot;</span><span class="p">])</span> <span class="k">if</span> <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;title&quot;</span><span class="p">]</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
            <span class="p">)</span>
            <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;subtitle&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                <span class="n">normalize</span><span class="p">(</span><span class="s2">&quot;NFKC&quot;</span><span class="p">,</span> <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;subtitle&quot;</span><span class="p">])</span>
                <span class="k">if</span> <span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;subtitle&quot;</span><span class="p">]</span>
                <span class="k">else</span> <span class="s2">&quot;&quot;</span>
            <span class="p">)</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">_db_moment_pk</span><span class="p">[</span><span class="n">moment_info</span><span class="p">[</span><span class="s2">&quot;pk&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">moment_info</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_build_album_folder_hierarchy_5</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">folders</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Recursively build folder/album hierarchy</span>
<span class="sd">        uuid: uuid of the album/folder being processed</span>
<span class="sd">        folders: dict holding the folder hierarchy&quot;&quot;&quot;</span>

        <span class="c1"># get parent uuid</span>
        <span class="n">parent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;parentfolder&quot;</span><span class="p">]</span>

        <span class="k">if</span> <span class="n">parent</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">parent_uuid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_pk</span><span class="p">[</span><span class="n">parent</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># folder with no parent (e.g. shared iCloud folders)</span>
            <span class="k">return</span> <span class="n">folders</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">&gt;</span> <span class="n">_PHOTOS_4_VERSION</span> <span class="ow">and</span> <span class="n">parent</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">_folder_root_pk</span><span class="p">:</span>
            <span class="c1"># at the top of the folder hierarchy, we&#39;re done</span>
            <span class="k">return</span> <span class="n">folders</span>

        <span class="c1"># recurse to keep building</span>
        <span class="n">folders</span> <span class="o">=</span> <span class="p">{</span><span class="n">parent_uuid</span><span class="p">:</span> <span class="n">folders</span><span class="p">}</span>
        <span class="n">folders</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_build_album_folder_hierarchy_5</span><span class="p">(</span><span class="n">parent_uuid</span><span class="p">,</span> <span class="n">folders</span><span class="o">=</span><span class="n">folders</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">folders</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_album_folder_hierarchy_list</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">album_uuid</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return appropriate album_folder_hierarchy_list for the _db_version&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">&lt;=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album_folder_hierarchy_list_4</span><span class="p">(</span><span class="n">album_uuid</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album_folder_hierarchy_list_5</span><span class="p">(</span><span class="n">album_uuid</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_album_folder_hierarchy_list_4</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">album_uuid</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return hierarchical list of folder names album_uuid is contained in</span>
<span class="sd">        the folder list is in form:</span>
<span class="sd">        [&quot;Top level folder&quot;, &quot;sub folder 1&quot;, &quot;sub folder 2&quot;]</span>
<span class="sd">        returns empty list of album is not in any folders&quot;&quot;&quot;</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">folders</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span>
        <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
            <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Caught _dbalbum_folders KeyError for album: </span><span class="si">{</span><span class="n">album_uuid</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
            <span class="k">return</span> <span class="p">[]</span>

        <span class="k">def</span><span class="w"> </span><span class="nf">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">,</span> <span class="n">hierarchy</span><span class="o">=</span><span class="p">[]):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Recursively walk the folders dict to build list of folder hierarchy&quot;&quot;&quot;</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">folders</span><span class="p">:</span>
                <span class="c1"># empty folder dict (album has no folder hierarchy)</span>
                <span class="k">return</span> <span class="p">[]</span>

            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">folders</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Expected only a single key in folders dict&quot;</span><span class="p">)</span>

            <span class="n">folder_uuid</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">folders</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>  <span class="c1"># first and only key of dict</span>

            <span class="n">parent_title</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbfolder_details</span><span class="p">[</span><span class="n">folder_uuid</span><span class="p">][</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>
            <span class="n">hierarchy</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">parent_title</span><span class="p">)</span>

            <span class="n">folders</span> <span class="o">=</span> <span class="n">folders</span><span class="p">[</span><span class="n">folder_uuid</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">folders</span><span class="p">:</span>
                <span class="c1"># still have elements left to recurse</span>
                <span class="n">hierarchy</span> <span class="o">=</span> <span class="n">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">,</span> <span class="n">hierarchy</span><span class="o">=</span><span class="n">hierarchy</span><span class="p">)</span>
                <span class="k">return</span> <span class="n">hierarchy</span>

            <span class="c1"># no elements left to recurse</span>
            <span class="k">return</span> <span class="n">hierarchy</span>

        <span class="n">hierarchy</span> <span class="o">=</span> <span class="n">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">hierarchy</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_album_folder_hierarchy_list_5</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">album_uuid</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return hierarchical list of folder names album_uuid is contained in</span>
<span class="sd">        the folder list is in form:</span>
<span class="sd">        [&quot;Top level folder&quot;, &quot;sub folder 1&quot;, &quot;sub folder 2&quot;]</span>
<span class="sd">        returns empty list of album is not in any folders&quot;&quot;&quot;</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">folders</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span>
        <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
            <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Caught _dbalbum_folders KeyError for album: </span><span class="si">{</span><span class="n">album_uuid</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
            <span class="k">return</span> <span class="p">[]</span>

        <span class="k">def</span><span class="w"> </span><span class="nf">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">,</span> <span class="n">hierarchy</span><span class="o">=</span><span class="p">[]):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Recursively walk the folders dict to build list of folder hierarchy&quot;&quot;&quot;</span>

            <span class="k">if</span> <span class="ow">not</span> <span class="n">folders</span><span class="p">:</span>
                <span class="c1"># empty folder dict (album has no folder hierarchy)</span>
                <span class="k">return</span> <span class="p">[]</span>

            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">folders</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Expected only a single key in folders dict&quot;</span><span class="p">)</span>

            <span class="n">folder_uuid</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">folders</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>  <span class="c1"># first and only key of dict</span>
            <span class="n">parent_title</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">[</span><span class="n">folder_uuid</span><span class="p">][</span><span class="s2">&quot;title&quot;</span><span class="p">]</span>
            <span class="n">hierarchy</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">parent_title</span><span class="p">)</span>

            <span class="n">folders</span> <span class="o">=</span> <span class="n">folders</span><span class="p">[</span><span class="n">folder_uuid</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">folders</span><span class="p">:</span>
                <span class="c1"># still have elements left to recurse</span>
                <span class="n">hierarchy</span> <span class="o">=</span> <span class="n">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">,</span> <span class="n">hierarchy</span><span class="o">=</span><span class="n">hierarchy</span><span class="p">)</span>
                <span class="k">return</span> <span class="n">hierarchy</span>

            <span class="c1"># no elements left to recurse</span>
            <span class="k">return</span> <span class="n">hierarchy</span>

        <span class="n">hierarchy</span> <span class="o">=</span> <span class="n">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">hierarchy</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_album_folder_hierarchy_folderinfo</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">album_uuid</span><span class="p">):</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">&lt;=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album_folder_hierarchy_folderinfo_4</span><span class="p">(</span><span class="n">album_uuid</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album_folder_hierarchy_folderinfo_5</span><span class="p">(</span><span class="n">album_uuid</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_album_folder_hierarchy_folderinfo_4</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">album_uuid</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return hierarchical list of FolderInfo objects album_uuid is contained in</span>
<span class="sd">        [&quot;Top level folder&quot;, &quot;sub folder 1&quot;, &quot;sub folder 2&quot;]</span>
<span class="sd">        returns empty list of album is not in any folders&quot;&quot;&quot;</span>
        <span class="c1"># title = photosdb._dbalbum_details[album_uuid][&quot;title&quot;]</span>
        <span class="n">folders</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span>
        <span class="c1"># logging.warning(f&quot;uuid = {album_uuid}, folder = {folders}&quot;)</span>

        <span class="k">def</span><span class="w"> </span><span class="nf">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">,</span> <span class="n">hierarchy</span><span class="o">=</span><span class="p">[]):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Recursively walk the folders dict to build list of folder hierarchy&quot;&quot;&quot;</span>
            <span class="c1"># logging.warning(f&quot;folders={folders},hierarchy = {hierarchy}&quot;)</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">folders</span><span class="p">:</span>
                <span class="c1"># empty folder dict (album has no folder hierarchy)</span>
                <span class="k">return</span> <span class="p">[]</span>

            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">folders</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Expected only a single key in folders dict&quot;</span><span class="p">)</span>

            <span class="n">folder_uuid</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">folders</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>  <span class="c1"># first and only key of dict</span>
            <span class="n">hierarchy</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">FolderInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">folder_uuid</span><span class="p">))</span>

            <span class="n">folders</span> <span class="o">=</span> <span class="n">folders</span><span class="p">[</span><span class="n">folder_uuid</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">folders</span><span class="p">:</span>
                <span class="c1"># still have elements left to recurse</span>
                <span class="n">hierarchy</span> <span class="o">=</span> <span class="n">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">,</span> <span class="n">hierarchy</span><span class="o">=</span><span class="n">hierarchy</span><span class="p">)</span>
                <span class="k">return</span> <span class="n">hierarchy</span>

            <span class="c1"># no elements left to recurse</span>
            <span class="k">return</span> <span class="n">hierarchy</span>

        <span class="n">hierarchy</span> <span class="o">=</span> <span class="n">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">)</span>
        <span class="c1"># logging.warning(f&quot;hierarchy = {hierarchy}&quot;)</span>
        <span class="k">return</span> <span class="n">hierarchy</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_album_folder_hierarchy_folderinfo_5</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">album_uuid</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return hierarchical list of FolderInfo objects album_uuid is contained in</span>
<span class="sd">        [&quot;Top level folder&quot;, &quot;sub folder 1&quot;, &quot;sub folder 2&quot;]</span>
<span class="sd">        returns empty list of album is not in any folders&quot;&quot;&quot;</span>
        <span class="c1"># title = photosdb._dbalbum_details[album_uuid][&quot;title&quot;]</span>
        <span class="n">folders</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_folders</span><span class="p">[</span><span class="n">album_uuid</span><span class="p">]</span>

        <span class="k">def</span><span class="w"> </span><span class="nf">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">,</span> <span class="n">hierarchy</span><span class="o">=</span><span class="p">[]):</span>
<span class="w">            </span><span class="sd">&quot;&quot;&quot;Recursively walk the folders dict to build list of folder hierarchy&quot;&quot;&quot;</span>

            <span class="k">if</span> <span class="ow">not</span> <span class="n">folders</span><span class="p">:</span>
                <span class="c1"># empty folder dict (album has no folder hierarchy)</span>
                <span class="k">return</span> <span class="p">[]</span>

            <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">folders</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
                <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Expected only a single key in folders dict&quot;</span><span class="p">)</span>

            <span class="n">folder_uuid</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">folders</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>  <span class="c1"># first and only key of dict</span>
            <span class="n">hierarchy</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">FolderInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">folder_uuid</span><span class="p">))</span>

            <span class="n">folders</span> <span class="o">=</span> <span class="n">folders</span><span class="p">[</span><span class="n">folder_uuid</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">folders</span><span class="p">:</span>
                <span class="c1"># still have elements left to recurse</span>
                <span class="n">hierarchy</span> <span class="o">=</span> <span class="n">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">,</span> <span class="n">hierarchy</span><span class="o">=</span><span class="n">hierarchy</span><span class="p">)</span>
                <span class="k">return</span> <span class="n">hierarchy</span>

            <span class="c1"># no elements left to recurse</span>
            <span class="k">return</span> <span class="n">hierarchy</span>

        <span class="n">hierarchy</span> <span class="o">=</span> <span class="n">_recurse_folder_hierarchy</span><span class="p">(</span><span class="n">folders</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">hierarchy</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_get_album_uuids</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">shared</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">import_session</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">project</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of album UUIDs found in photos database</span>

<span class="sd">            Filters out albums in the trash and any special album types</span>

<span class="sd">        Args:</span>
<span class="sd">            shared: boolean; if True, returns shared albums, else normal albums</span>
<span class="sd">            import_session: boolean, if True, returns import session albums, else normal or shared albums</span>
<span class="sd">            project: boolean, if True, returns albums that are part of My Projects</span>
<span class="sd">            Note: flags (shared, import_session) are mutually exclusive</span>


<span class="sd">        Raises:</span>
<span class="sd">            ValueError: raised if mutually exclusive flags passed</span>

<span class="sd">        Returns: list of album UUIDs</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="nb">sum</span><span class="p">(</span><span class="nb">bool</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">[</span><span class="n">shared</span><span class="p">,</span> <span class="n">import_session</span><span class="p">,</span> <span class="n">project</span><span class="p">])</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
                <span class="s2">&quot;flags are mutually exclusive: pass zero or one of shared, import_session, projects&quot;</span>
            <span class="p">)</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">&lt;=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">shared</span><span class="p">:</span>
                <span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
                    <span class="sa">f</span><span class="s2">&quot;Shared albums not implemented for Photos library version </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span><span class="si">}</span><span class="s2">&quot;</span>
                <span class="p">)</span>
                <span class="k">return</span> <span class="p">[]</span>  <span class="c1"># not implemented for _PHOTOS_4_VERSION</span>
            <span class="k">elif</span> <span class="n">import_session</span><span class="p">:</span>
                <span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
                    <span class="sa">f</span><span class="s2">&quot;Import sessions not implemented for Photos library version </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span><span class="si">}</span><span class="s2">&quot;</span>
                <span class="p">)</span>
                <span class="k">return</span> <span class="p">[]</span>  <span class="c1"># not implemented for _PHOTOS_4_VERSION</span>
            <span class="k">elif</span> <span class="n">project</span><span class="p">:</span>
                <span class="n">album_type</span> <span class="o">=</span> <span class="p">[</span>
                    <span class="n">_PHOTOS_4_ALBUM_TYPE_PROJECT</span><span class="p">,</span>
                    <span class="n">_PHOTOS_4_ALBUM_TYPE_SLIDESHOW</span><span class="p">,</span>
                <span class="p">]</span>
                <span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_4_ALBUM_KIND</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">album_type</span> <span class="o">=</span> <span class="p">[</span><span class="n">_PHOTOS_4_ALBUM_TYPE_ALBUM</span><span class="p">]</span>
                <span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_4_ALBUM_KIND</span>

            <span class="n">album_list</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="c1"># look through _dbalbum_details because _dbalbums_album won&#39;t have empty albums it</span>
            <span class="k">for</span> <span class="n">album</span><span class="p">,</span> <span class="n">detail</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
                <span class="k">if</span> <span class="p">(</span>
                    <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;kind&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">album_kind</span>
                    <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;albumType&quot;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">album_type</span>
                    <span class="ow">and</span> <span class="ow">not</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;intrash&quot;</span><span class="p">]</span>
                    <span class="ow">and</span> <span class="p">(</span>
                        <span class="p">(</span><span class="n">shared</span> <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;cloudownerhashedpersonid&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">)</span>
                        <span class="ow">or</span> <span class="p">(</span><span class="ow">not</span> <span class="n">shared</span> <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;cloudownerhashedpersonid&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">)</span>
                    <span class="p">)</span>
                    <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;folderUuid&quot;</span><span class="p">]</span> <span class="o">!=</span> <span class="n">_PHOTOS_4_ROOT_FOLDER</span>
                    <span class="c1"># in Photos &lt;= 4, special albums like &quot;printAlbum&quot; have kind _PHOTOS_4_ALBUM_KIND</span>
                    <span class="c1"># but should not be listed here; they can be distinguished by looking</span>
                    <span class="c1"># for folderUuid of _PHOTOS_4_ROOT_FOLDER as opposed to _PHOTOS_4_TOP_LEVEL_ALBUM</span>
                <span class="p">):</span>
                    <span class="n">album_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">album</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">album_list</span>

        <span class="c1"># Photos version 5+</span>
        <span class="k">if</span> <span class="n">shared</span><span class="p">:</span>
            <span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_5_SHARED_ALBUM_KIND</span>
        <span class="k">elif</span> <span class="n">import_session</span><span class="p">:</span>
            <span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_5_IMPORT_SESSION_ALBUM_KIND</span>
        <span class="k">elif</span> <span class="n">project</span><span class="p">:</span>
            <span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_5_PROJECT_ALBUM_KIND</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">album_kind</span> <span class="o">=</span> <span class="n">_PHOTOS_5_ALBUM_KIND</span>

        <span class="n">album_list</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="c1"># look through _dbalbum_details because _dbalbums_album won&#39;t have empty albums it</span>
        <span class="k">for</span> <span class="n">album</span><span class="p">,</span> <span class="n">detail</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="k">if</span> <span class="p">(</span>
                <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;kind&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">album_kind</span>
                <span class="ow">and</span> <span class="ow">not</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;intrash&quot;</span><span class="p">]</span>
                <span class="ow">and</span> <span class="p">(</span>
                    <span class="p">(</span><span class="n">shared</span> <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;cloudownerhashedpersonid&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">)</span>
                    <span class="ow">or</span> <span class="p">(</span><span class="ow">not</span> <span class="n">shared</span> <span class="ow">and</span> <span class="n">detail</span><span class="p">[</span><span class="s2">&quot;cloudownerhashedpersonid&quot;</span><span class="p">]</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">)</span>
                <span class="p">)</span>
            <span class="p">):</span>
                <span class="n">album_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">album</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">album_list</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_get_albums</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">shared</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of album titles found in photos database</span>
<span class="sd">            Albums may have duplicate titles -- these will be treated as a single album.</span>

<span class="sd">            Filters out albums in the trash and any special album types</span>

<span class="sd">        Args:</span>
<span class="sd">            shared: boolean; if True, returns shared albums, else normal albums</span>

<span class="sd">        Returns: list of album names</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="n">album_uuids</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_album_uuids</span><span class="p">(</span><span class="n">shared</span><span class="o">=</span><span class="n">shared</span><span class="p">)</span>
        <span class="k">return</span> <span class="nb">list</span><span class="p">({</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_details</span><span class="p">[</span><span class="n">album</span><span class="p">][</span><span class="s2">&quot;title&quot;</span><span class="p">]</span> <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">album_uuids</span><span class="p">})</span>

<div class="viewcode-block" id="PhotosDB.photos">
<a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB.photos">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">photos</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span>
        <span class="n">keywords</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">uuid</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">persons</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">albums</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">images</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
        <span class="n">movies</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
        <span class="n">from_date</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">datetime</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">to_date</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">datetime</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">intrash</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
    <span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">PhotoInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return a list of PhotoInfo objects</span>
<span class="sd">        If called with no args, returns the entire database of photos</span>
<span class="sd">        If called with args, returns photos matching the args (e.g. keywords, persons, etc.)</span>
<span class="sd">        If more than one arg, returns photos matching all the criteria (e.g. keywords AND persons)</span>
<span class="sd">        If more than one keyword, uuid, persons, albums is passed, they are treated as &quot;OR&quot; criteria</span>
<span class="sd">        e.g. keywords=[&quot;wedding&quot;,&quot;vacation&quot;] returns photos matching either keyword</span>
<span class="sd">        from_date and to_date may be either naive or timezone-aware datetime.datetime objects.</span>
<span class="sd">        If naive, timezone will be assumed to be local timezone.</span>

<span class="sd">        Args:</span>
<span class="sd">            keywords: list of keywords to search for</span>
<span class="sd">            uuid: list of UUIDs to search for</span>
<span class="sd">            persons: list of persons to search for</span>
<span class="sd">            albums: list of album names to search for</span>
<span class="sd">            images: if True, returns image files, if False, does not return images; default is True</span>
<span class="sd">            movies: if True, returns movie files, if False, does not return movies; default is True</span>
<span class="sd">            from_date: return photos with creation date &gt;= from_date (datetime.datetime object, default None)</span>
<span class="sd">            to_date: return photos with creation date &lt; to_date (datetime.datetime object, default None)</span>
<span class="sd">            intrash: if True, returns only images in &quot;Recently deleted items&quot; folder,</span>
<span class="sd">                     if False returns only photos that aren&#39;t deleted; default is False</span>

<span class="sd">        Returns:</span>
<span class="sd">            list of PhotoInfo objects</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="c1"># implementation is a bit kludgy but it works</span>
        <span class="c1"># build a set of each search argument then compute the intersection of the sets</span>
        <span class="c1"># use results to build a list of PhotoInfo objects</span>

        <span class="n">photos_sets</span> <span class="o">=</span> <span class="p">[]</span>  <span class="c1"># list of photo sets to perform intersection of</span>
        <span class="k">if</span> <span class="n">intrash</span><span class="p">:</span>
            <span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
                <span class="p">{</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="s2">&quot;intrash&quot;</span><span class="p">]}</span>
            <span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
                <span class="p">{</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="s2">&quot;intrash&quot;</span><span class="p">]}</span>
            <span class="p">)</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">([</span><span class="n">keywords</span><span class="p">,</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">persons</span><span class="p">,</span> <span class="n">albums</span><span class="p">,</span> <span class="n">from_date</span><span class="p">,</span> <span class="n">to_date</span><span class="p">]):</span>
            <span class="c1"># return all the photos, filtering for images and movies</span>
            <span class="c1"># append keys of all photos as a single set to photos_sets</span>
            <span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="o">.</span><span class="n">keys</span><span class="p">()))</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">albums</span><span class="p">:</span>
                <span class="n">album_set</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
                <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">albums</span><span class="p">:</span>
                    <span class="c1"># glob together albums with same name</span>
                    <span class="k">if</span> <span class="n">album</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_titles</span><span class="p">:</span>
                        <span class="n">title_set</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
                        <span class="k">for</span> <span class="n">album_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbalbum_titles</span><span class="p">[</span><span class="n">album</span><span class="p">]:</span>
                            <span class="k">try</span><span class="p">:</span>
                                <span class="c1"># _dbalbums_album value is list of tuples: [(uuid, sort order)]</span>
                                <span class="n">uuid_in_album</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="nb">zip</span><span class="p">(</span><span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbalbums_album</span><span class="p">[</span><span class="n">album_id</span><span class="p">])</span>
                                <span class="n">title_set</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">uuid_in_album</span><span class="p">)</span>
                            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                                <span class="c1"># an empty album will be in _dbalbum_titles but not _dbalbums_album</span>
                                <span class="k">pass</span>
                        <span class="n">album_set</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">title_set</span><span class="p">)</span>
                <span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">album_set</span><span class="p">)</span>

            <span class="k">if</span> <span class="n">uuid</span><span class="p">:</span>
                <span class="n">uuid_set</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
                <span class="k">for</span> <span class="n">u</span> <span class="ow">in</span> <span class="n">uuid</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">u</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
                        <span class="n">uuid_set</span><span class="o">.</span><span class="n">update</span><span class="p">([</span><span class="n">u</span><span class="p">])</span>
                <span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">uuid_set</span><span class="p">)</span>

            <span class="k">if</span> <span class="n">keywords</span><span class="p">:</span>
                <span class="n">keyword_set</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
                <span class="k">for</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">keywords</span><span class="p">:</span>
                    <span class="n">keyword</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">keyword</span><span class="p">)</span>
                    <span class="k">if</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">:</span>
                        <span class="n">keyword_set</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword</span><span class="p">])</span>
                <span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword_set</span><span class="p">)</span>

            <span class="k">if</span> <span class="n">persons</span><span class="p">:</span>
                <span class="n">person_set</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
                <span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="n">persons</span><span class="p">:</span>
                    <span class="n">person</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">person</span><span class="p">)</span>
                    <span class="k">if</span> <span class="n">person</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_fullname</span><span class="p">:</span>
                        <span class="k">for</span> <span class="n">pk</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbpersons_fullname</span><span class="p">[</span><span class="n">person</span><span class="p">]:</span>
                            <span class="k">try</span><span class="p">:</span>
                                <span class="n">person_set</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbfaces_pk</span><span class="p">[</span><span class="n">pk</span><span class="p">])</span>
                            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
                                <span class="c1"># some persons have zero photos so they won&#39;t be in _dbfaces_pk</span>
                                <span class="k">pass</span>
                <span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">person_set</span><span class="p">)</span>

            <span class="k">if</span> <span class="n">from_date</span> <span class="ow">or</span> <span class="n">to_date</span><span class="p">:</span>  <span class="c1"># sourcery off</span>
                <span class="n">dsel</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span>
                <span class="k">if</span> <span class="n">from_date</span><span class="p">:</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="n">datetime_has_tz</span><span class="p">(</span><span class="n">from_date</span><span class="p">):</span>
                        <span class="n">from_date</span> <span class="o">=</span> <span class="n">datetime_naive_to_local</span><span class="p">(</span><span class="n">from_date</span><span class="p">)</span>
                    <span class="n">dsel</span> <span class="o">=</span> <span class="p">{</span>
                        <span class="n">k</span><span class="p">:</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">dsel</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">v</span><span class="p">[</span><span class="s2">&quot;imageDate&quot;</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">from_date</span>
                    <span class="p">}</span>
                <span class="k">if</span> <span class="n">to_date</span><span class="p">:</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="n">datetime_has_tz</span><span class="p">(</span><span class="n">to_date</span><span class="p">):</span>
                        <span class="n">to_date</span> <span class="o">=</span> <span class="n">datetime_naive_to_local</span><span class="p">(</span><span class="n">to_date</span><span class="p">)</span>
                    <span class="n">dsel</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">dsel</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">v</span><span class="p">[</span><span class="s2">&quot;imageDate&quot;</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">to_date</span><span class="p">}</span>
                <span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">dsel</span><span class="o">.</span><span class="n">keys</span><span class="p">()))</span>

        <span class="n">photoinfo</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">if</span> <span class="n">photos_sets</span><span class="p">:</span>  <span class="c1"># found some photos</span>
            <span class="c1"># get the intersection of each argument/search criteria</span>
            <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="nb">set</span><span class="o">.</span><span class="n">intersection</span><span class="p">(</span><span class="o">*</span><span class="n">photos_sets</span><span class="p">):</span>
                <span class="c1"># filter for non-selected burst photos</span>
                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="s2">&quot;burst&quot;</span><span class="p">]</span> <span class="ow">and</span> <span class="ow">not</span> <span class="p">(</span>
                    <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="s2">&quot;burstPickType&quot;</span><span class="p">]</span> <span class="o">&amp;</span> <span class="n">BURST_SELECTED</span>
                    <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="s2">&quot;burstPickType&quot;</span><span class="p">]</span> <span class="o">&amp;</span> <span class="n">BURST_KEY</span>
                    <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="s2">&quot;burstPickType&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">BURST_PICK_TYPE_NONE</span>
                <span class="p">):</span>
                    <span class="c1"># not a key/selected burst photo, don&#39;t include in returned results</span>
                    <span class="k">continue</span>

                <span class="c1"># filter for images and/or movies</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">images</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="s2">&quot;type&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">_PHOTO_TYPE</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span>
                    <span class="n">movies</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">][</span><span class="s2">&quot;type&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">_MOVIE_TYPE</span>
                <span class="p">):</span>
                    <span class="n">info</span> <span class="o">=</span> <span class="n">PhotoInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">p</span><span class="p">,</span> <span class="n">info</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">p</span><span class="p">])</span>
                    <span class="n">photoinfo</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">info</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">photoinfo</span></div>


<div class="viewcode-block" id="PhotosDB.get_photo">
<a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB.get_photo">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_photo</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns a single photo matching uuid</span>

<span class="sd">        Arguments:</span>
<span class="sd">            uuid: the UUID of photo to get</span>

<span class="sd">        Returns:</span>
<span class="sd">            PhotoInfo instance for photo with UUID matching uuid or None if no match</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">PhotoInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">uuid</span><span class="p">,</span> <span class="n">info</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">])</span>
        <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">None</span></div>


<div class="viewcode-block" id="PhotosDB.photos_by_uuid">
<a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB.photos_by_uuid">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">photos_by_uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuids</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns a list of photos with UUID in uuids.</span>
<span class="sd">            Does not generate error if invalid or missing UUID passed.</span>
<span class="sd">            This is faster than using PhotosDB.photos if you have list of UUIDs.</span>
<span class="sd">            Returns photos regardless of intrash state.</span>

<span class="sd">        Arguments:</span>
<span class="sd">            uuid: list of UUIDs of photos to get</span>

<span class="sd">        Returns:</span>
<span class="sd">            list of PhotoInfo instance for photo with UUID matching uuid or [] if no match</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">[</span>
            <span class="n">PhotoInfo</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="n">uuid</span><span class="p">,</span> <span class="n">info</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">])</span>
            <span class="k">for</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="n">uuids</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span>
        <span class="p">]</span></div>


<div class="viewcode-block" id="PhotosDB.query">
<a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB.query">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">query</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">options</span><span class="p">:</span> <span class="n">QueryOptions</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">PhotoInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Run a query against PhotosDB to extract the photos based on user supplied options</span>

<span class="sd">        Args:</span>
<span class="sd">            options: a QueryOptions instance</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">photo_query</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">options</span><span class="p">)</span></div>


<div class="viewcode-block" id="PhotosDB.execute">
<a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB.execute">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">execute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">params</span><span class="p">:</span> <span class="n">Any</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Cursor</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Execute sql statement and return cursor&quot;&quot;&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_connection</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_db_connection</span><span class="p">()</span>
        <span class="n">params</span> <span class="o">=</span> <span class="n">params</span> <span class="ow">or</span> <span class="p">()</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_connection</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="n">params</span><span class="p">)</span></div>


    <span class="k">def</span><span class="w"> </span><span class="nf">_duplicate_signature</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Compute a signature for finding possible duplicates&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">(</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;original_filesize&quot;</span><span class="p">],</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;imageDate&quot;</span><span class="p">],</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;height&quot;</span><span class="p">],</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;width&quot;</span><span class="p">],</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;UTI&quot;</span><span class="p">],</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;hasAdjustments&quot;</span><span class="p">],</span>
        <span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;osxphotos.</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">(dbfile=&#39;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">db_path</span><span class="si">}</span><span class="s2">&#39;)&quot;</span>

    <span class="c1"># compare two PhotosDB objects for equality</span>
    <span class="k">def</span><span class="w"> </span><span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="p">):</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__dict__</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="vm">__dict__</span>

        <span class="k">return</span> <span class="kc">False</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns number of photos in the database</span>
<span class="sd">        Includes recently deleted photos and non-selected burst images</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__del__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">if</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&quot;_db_connection&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_connection</span><span class="o">.</span><span class="n">close</span><span class="p">()</span></div>

</pre></div>
        </article>
      </div>
      <footer>
        
        <div class="related-pages">
          
          
        </div>
        <div class="bottom-of-page">
          <div class="left-details">
            <div class="copyright">
                Copyright &#169; 2021, Rhet Turnbull
            </div>
            Made with <a href="https://www.sphinx-doc.org/">Sphinx</a> and <a class="muted-link" href="https://pradyunsg.me">@pradyunsg</a>'s
            
            <a href="https://github.com/pradyunsg/furo">Furo</a>
            
          </div>
          <div class="right-details">
            
          </div>
        </div>
        
      </footer>
    </div>
    <aside class="toc-drawer no-toc">
      
      
      
    </aside>
  </div>
</div><script src="../../../_static/documentation_options.js?v=63568c49"></script>
    <script src="../../../_static/doctools.js?v=9bcbadda"></script>
    <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
    <script src="../../../_static/scripts/furo.js?v=46bd48cc"></script>
    <script src="../../../_static/clipboard.min.js?v=a7894cd8"></script>
    <script src="../../../_static/copybutton.js?v=f281be69"></script>
    </body>
</html>